DockEventReceiver.java revision 2036ebd8896bbabbbe04db34c9e7d8a1be6fe32a
1df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan/*
2df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * Copyright (C) 2009 The Android Open Source Project
3df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan *
4df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * Licensed under the Apache License, Version 2.0 (the "License");
5df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * you may not use this file except in compliance with the License.
6df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * You may obtain a copy of the License at
7df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan *
8df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan *      http://www.apache.org/licenses/LICENSE-2.0
9df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan *
10df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * Unless required by applicable law or agreed to in writing, software
11df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * distributed under the License is distributed on an "AS IS" BASIS,
12df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * See the License for the specific language governing permissions and
14df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan * limitations under the License.
15df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan */
16df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
17df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanpackage com.android.settings.bluetooth;
18df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
19df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.app.Service;
20732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport android.bluetooth.BluetoothA2dp;
21fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chanimport android.bluetooth.BluetoothAdapter;
22df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.bluetooth.BluetoothDevice;
23732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport android.bluetooth.BluetoothHeadset;
245809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
25df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.BroadcastReceiver;
26df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.Context;
27df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.Intent;
28df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.os.PowerManager;
29df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.util.Log;
30df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
31436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hambypublic final class DockEventReceiver extends BroadcastReceiver {
32df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
33845e740fc63657438b9085376c8e7d60d8334a72Michael Chan    private static final boolean DEBUG = DockService.DEBUG;
34df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
35df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    private static final String TAG = "DockEventReceiver";
36df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
37df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public static final String ACTION_DOCK_SHOW_UI =
38df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        "com.android.settings.bluetooth.action.DOCK_SHOW_UI";
39df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
40df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    private static final int EXTRA_INVALID = -1234;
41df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
42436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static final Object sStartingServiceSync = new Object();
43df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
44436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static PowerManager.WakeLock sStartingService;
45df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
46df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    @Override
47df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public void onReceive(Context context, Intent intent) {
48df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (intent == null)
49df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            return;
50df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
513fe86a346cdcd41fd9498591571d8b512a130240Michael Chan        int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, intent.getIntExtra(
523fe86a346cdcd41fd9498591571d8b512a130240Michael Chan                BluetoothAdapter.EXTRA_STATE, EXTRA_INVALID));
53df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
54df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
55df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (DEBUG) {
56df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            Log.d(TAG, "Action: " + intent.getAction() + " State:" + state + " Device: "
572036ebd8896bbabbbe04db34c9e7d8a1be6fe32aMatthew Xie                    + (device == null ? "null" : device.getAliasName()));
58df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
59df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
60df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())
61df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                || ACTION_DOCK_SHOW_UI.endsWith(intent.getAction())) {
62df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (device == null) {
63503c236db541b3d7c8278fa63afe4d1b792ac9a9Michael Chan                if (DEBUG) Log.d(TAG, "Device is missing");
64df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                return;
65df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
66df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
67df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            switch (state) {
68df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_UNDOCKED:
69df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_CAR:
70df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_DESK:
71df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    Intent i = new Intent(intent);
72df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    i.setClass(context, DockService.class);
73df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    beginStartingService(context, i);
74df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    break;
75df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                default:
76436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    Log.e(TAG, "Unknown state: " + state);
77df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    break;
78df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
795809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction()) ||
805809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                   BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
815809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
825809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                    BluetoothProfile.STATE_CONNECTED);
835809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
845809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh
85732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            /*
86732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  Reconnect to the dock if:
87732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  1) it is a dock
88732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  2) it is disconnected
89732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  3) the disconnect is initiated remotely
90732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  4) the dock is still docked (check can only be done in the Service)
91732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             */
92732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            if (device == null) {
93732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                if (DEBUG) Log.d(TAG, "Device is missing");
94732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                return;
95732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            }
96732c1dad5a4871597652f17986b7a602897e5a76Michael Chan
975809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
985809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                    oldState != BluetoothProfile.STATE_DISCONNECTING) {
99732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                // Too bad, the dock state can't be checked from a BroadcastReceiver.
100732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                Intent i = new Intent(intent);
101732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                i.setClass(context, DockService.class);
102732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                beginStartingService(context, i);
103732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            }
104732c1dad5a4871597652f17986b7a602897e5a76Michael Chan
105845e740fc63657438b9085376c8e7d60d8334a72Michael Chan        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
106845e740fc63657438b9085376c8e7d60d8334a72Michael Chan            int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
1073fe86a346cdcd41fd9498591571d8b512a130240Michael Chan            if (btState != BluetoothAdapter.STATE_TURNING_ON) {
108845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                Intent i = new Intent(intent);
109845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                i.setClass(context, DockService.class);
110845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                beginStartingService(context, i);
111845e740fc63657438b9085376c8e7d60d8334a72Michael Chan            }
112df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
113df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
114df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
115df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    /**
116df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * Start the service to process the current event notifications, acquiring
117df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * the wake lock before returning to ensure that the service will run.
118df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     */
119436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby    private static void beginStartingService(Context context, Intent intent) {
120436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        synchronized (sStartingServiceSync) {
121436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sStartingService == null) {
122df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
123436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                sStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
124df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                        "StartingDockService");
125df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
126df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
127436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            sStartingService.acquire();
128df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
129df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (context.startService(intent) == null) {
130df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                Log.e(TAG, "Can't start DockService");
131df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
132df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
133df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
134df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
135df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    /**
136df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * Called back by the service when it has finished processing notifications,
137df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * releasing the wake lock if the service is now stopping.
138df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     */
139df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public static void finishStartingService(Service service, int startId) {
140436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby        synchronized (sStartingServiceSync) {
141436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby            if (sStartingService != null) {
142436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (DEBUG) Log.d(TAG, "stopSelf id = " + startId);
143436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                if (service.stopSelfResult(startId)) {
144436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    Log.d(TAG, "finishStartingService: stopping service");
145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                    sStartingService.release();
146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby                }
147df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
148df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
149df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
150df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan}
151