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())) { 62f892bc856c6780187db62681d59ca538a173590fEric Laurent if ((device == null) && (ACTION_DOCK_SHOW_UI.endsWith(intent.getAction()) || 63f892bc856c6780187db62681d59ca538a173590fEric Laurent ((state != Intent.EXTRA_DOCK_STATE_UNDOCKED) && 64f892bc856c6780187db62681d59ca538a173590fEric Laurent (state != Intent.EXTRA_DOCK_STATE_LE_DESK)))) { 65f892bc856c6780187db62681d59ca538a173590fEric Laurent if (DEBUG) Log.d(TAG, 66f892bc856c6780187db62681d59ca538a173590fEric Laurent "Wrong state: "+state+" or intent: "+intent.toString()+" with null device"); 67df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan return; 68df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 69df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan 70df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan switch (state) { 71df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan case Intent.EXTRA_DOCK_STATE_UNDOCKED: 72df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan case Intent.EXTRA_DOCK_STATE_CAR: 73df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan case Intent.EXTRA_DOCK_STATE_DESK: 74b8dd637887606242c5cbeaa2fa952946f9013d8fJeff Brown case Intent.EXTRA_DOCK_STATE_LE_DESK: 75b8dd637887606242c5cbeaa2fa952946f9013d8fJeff Brown case Intent.EXTRA_DOCK_STATE_HE_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: 81436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.e(TAG, "Unknown state: " + 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 */ 124436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby private static void beginStartingService(Context context, Intent intent) { 125436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (sStartingServiceSync) { 126436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (sStartingService == null) { 127df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 128436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby sStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 129df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan "StartingDockService"); 130df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 131df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan 132436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby sStartingService.acquire(); 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) { 145436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby synchronized (sStartingServiceSync) { 146436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (sStartingService != null) { 147436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (DEBUG) Log.d(TAG, "stopSelf id = " + startId); 148436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby if (service.stopSelfResult(startId)) { 149436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby Log.d(TAG, "finishStartingService: stopping service"); 150436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby sStartingService.release(); 151436b29e68e6608bed9e8e7d54385b8f62d89208eJake Hamby } 152df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 153df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 154df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan } 155df9504ef58e8dafdd80ca9cd780510f9444943e2Michael Chan} 156