DockEventReceiver.java revision 5809d33296d60f54c7e93de2f45bd84579f70449
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
19732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
20732c1dad5a4871597652f17986b7a602897e5a76Michael Chan
21df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.app.Service;
22732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport android.bluetooth.BluetoothA2dp;
23fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chanimport android.bluetooth.BluetoothAdapter;
24df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.bluetooth.BluetoothDevice;
25732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport android.bluetooth.BluetoothHeadset;
265809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
27df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.BroadcastReceiver;
28df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.Context;
29df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.content.Intent;
30732c1dad5a4871597652f17986b7a602897e5a76Michael Chanimport android.content.IntentFilter;
31df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.os.PowerManager;
32df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanimport android.util.Log;
33df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
34df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chanpublic class DockEventReceiver extends BroadcastReceiver {
35df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
36845e740fc63657438b9085376c8e7d60d8334a72Michael Chan    private static final boolean DEBUG = DockService.DEBUG;
37df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
38df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    private static final String TAG = "DockEventReceiver";
39df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
40df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public static final String ACTION_DOCK_SHOW_UI =
41df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        "com.android.settings.bluetooth.action.DOCK_SHOW_UI";
42df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
43df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    private static final int EXTRA_INVALID = -1234;
44df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
45fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan    private static final Object mStartingServiceSync = new Object();
46df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
47fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan    private static final long WAKELOCK_TIMEOUT = 5000;
48fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan
49fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan    private static PowerManager.WakeLock mStartingService;
50df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
51df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    @Override
52df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public void onReceive(Context context, Intent intent) {
53df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (intent == null)
54df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            return;
55df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
563fe86a346cdcd41fd9498591571d8b512a130240Michael Chan        int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, intent.getIntExtra(
573fe86a346cdcd41fd9498591571d8b512a130240Michael Chan                BluetoothAdapter.EXTRA_STATE, EXTRA_INVALID));
58df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
59df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
60df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (DEBUG) {
61df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            Log.d(TAG, "Action: " + intent.getAction() + " State:" + state + " Device: "
62df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    + (device == null ? "null" : device.getName()));
63df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
64df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
65df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())
66df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                || ACTION_DOCK_SHOW_UI.endsWith(intent.getAction())) {
67df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (device == null) {
68503c236db541b3d7c8278fa63afe4d1b792ac9a9Michael Chan                if (DEBUG) Log.d(TAG, "Device is missing");
69df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                return;
70df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
71df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
72df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            switch (state) {
73df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_UNDOCKED:
74df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_CAR:
75df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                case Intent.EXTRA_DOCK_STATE_DESK:
76df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    Intent i = new Intent(intent);
77df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    i.setClass(context, DockService.class);
78df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    beginStartingService(context, i);
79df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    break;
80df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                default:
81df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    if (DEBUG) Log.e(TAG, "Unknown state");
82df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                    break;
83df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
845809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction()) ||
855809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                   BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
865809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
875809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                    BluetoothProfile.STATE_CONNECTED);
885809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
895809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh
90732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            /*
91732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  Reconnect to the dock if:
92732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  1) it is a dock
93732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  2) it is disconnected
94732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  3) the disconnect is initiated remotely
95732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             *  4) the dock is still docked (check can only be done in the Service)
96732c1dad5a4871597652f17986b7a602897e5a76Michael Chan             */
97732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            if (device == null) {
98732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                if (DEBUG) Log.d(TAG, "Device is missing");
99732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                return;
100732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            }
101732c1dad5a4871597652f17986b7a602897e5a76Michael Chan
1025809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
1035809d33296d60f54c7e93de2f45bd84579f70449Jaikumar Ganesh                    oldState != BluetoothProfile.STATE_DISCONNECTING) {
104732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                // Too bad, the dock state can't be checked from a BroadcastReceiver.
105732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                Intent i = new Intent(intent);
106732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                i.setClass(context, DockService.class);
107732c1dad5a4871597652f17986b7a602897e5a76Michael Chan                beginStartingService(context, i);
108732c1dad5a4871597652f17986b7a602897e5a76Michael Chan            }
109732c1dad5a4871597652f17986b7a602897e5a76Michael Chan
110845e740fc63657438b9085376c8e7d60d8334a72Michael Chan        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
111845e740fc63657438b9085376c8e7d60d8334a72Michael Chan            int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
1123fe86a346cdcd41fd9498591571d8b512a130240Michael Chan            if (btState != BluetoothAdapter.STATE_TURNING_ON) {
113845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                Intent i = new Intent(intent);
114845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                i.setClass(context, DockService.class);
115845e740fc63657438b9085376c8e7d60d8334a72Michael Chan                beginStartingService(context, i);
116845e740fc63657438b9085376c8e7d60d8334a72Michael Chan            }
117df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
118df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
119df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
120df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    /**
121df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * Start the service to process the current event notifications, acquiring
122df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * the wake lock before returning to ensure that the service will run.
123df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     */
124df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public static void beginStartingService(Context context, Intent intent) {
125df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        synchronized (mStartingServiceSync) {
126df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (mStartingService == null) {
127df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
128df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
129df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                        "StartingDockService");
130df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
131df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
132fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan            mStartingService.acquire(WAKELOCK_TIMEOUT);
133df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
134df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (context.startService(intent) == null) {
135df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan                Log.e(TAG, "Can't start DockService");
136df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
137df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
138df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
139df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan
140df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    /**
141df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * Called back by the service when it has finished processing notifications,
142df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     * releasing the wake lock if the service is now stopping.
143df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan     */
144df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    public static void finishStartingService(Service service, int startId) {
145df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        synchronized (mStartingServiceSync) {
146df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            if (mStartingService != null) {
147146385663bb55d9f55ad179d3c35ccf5cac13fc8Michael Chan                if (DEBUG) Log.d(TAG, "stopSelf id = "+ startId);
148fb5b54d77aee1b2d6a0c0ffe7d47c73a204dee28Michael Chan                service.stopSelfResult(startId);
149df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan            }
150df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan        }
151df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan    }
152df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan}
153