diff options
author | Nitin Arora <niarora@codeaurora.org> | 2015-03-11 15:45:26 -0700 |
---|---|---|
committer | Andre Eisenbach <eisenbach@google.com> | 2015-04-15 23:30:10 -0700 |
commit | f19f1ac64a5fefb248ab15b918d009b926c99dde (patch) | |
tree | 8b5e76134add97468a8d4801fb51d12dd5573003 | |
parent | dbe4c2517804b3e32587310b76f1c977b8749d8b (diff) | |
download | android_packages_apps_Bluetooth-f19f1ac64a5fefb248ab15b918d009b926c99dde.tar.gz android_packages_apps_Bluetooth-f19f1ac64a5fefb248ab15b918d009b926c99dde.tar.bz2 android_packages_apps_Bluetooth-f19f1ac64a5fefb248ab15b918d009b926c99dde.zip |
Bluetooth LE background operation mode (1/2)
Changes to BluetoothAdapter state machine for handling new
states BLE_STATE_ON and intermediate states BLE_TURNING_ON
and BLE_TURNING_OFF. Also includes the actions required
while migrating in and out of these states including
start and stop of GATT services and other profiles.
Change-Id: I08d6ff05c2cefe559d5bb5789a1a488afefbe544
-rw-r--r-- | jni/com_android_bluetooth_avrcp.cpp | 47 | ||||
-rw-r--r--[-rwxr-xr-x] | jni/com_android_bluetooth_hid.cpp | 0 | ||||
-rw-r--r-- | jni/com_android_bluetooth_pan.cpp | 9 | ||||
-rw-r--r-- | src/com/android/bluetooth/btservice/AdapterProperties.java | 14 | ||||
-rw-r--r-- | src/com/android/bluetooth/btservice/AdapterService.java | 183 | ||||
-rw-r--r--[-rwxr-xr-x] | src/com/android/bluetooth/btservice/AdapterState.java | 312 | ||||
-rw-r--r-- | src/com/android/bluetooth/btservice/ProfileService.java | 5 | ||||
-rw-r--r-- | src/com/android/bluetooth/btservice/RemoteDevices.java | 20 | ||||
-rw-r--r-- | src/com/android/bluetooth/gatt/ContextMap.java | 13 | ||||
-rw-r--r-- | src/com/android/bluetooth/gatt/GattService.java | 31 | ||||
-rwxr-xr-x | src/com/android/bluetooth/hid/HidService.java | 2 |
11 files changed, 493 insertions, 143 deletions
diff --git a/jni/com_android_bluetooth_avrcp.cpp b/jni/com_android_bluetooth_avrcp.cpp index e9a7bc90d..b28a43e30 100644 --- a/jni/com_android_bluetooth_avrcp.cpp +++ b/jni/com_android_bluetooth_avrcp.cpp @@ -59,13 +59,18 @@ static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr, btrc_remote_f } addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { - ALOGE("Fail to new jbyteArray bd addr for connection state"); + ALOGE("Unable to allocate byte array for bd_addr"); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); return; } - sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features); + if (mCallbacksObj) { + sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } + checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); /* TODO: I think we leak the addr object, we should add a * sCallbackEnv->DeleteLocalRef(addr) */ @@ -79,7 +84,11 @@ static void btavrcp_get_play_status_callback() { return; } - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus); + if (mCallbacksObj) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); } @@ -99,7 +108,11 @@ static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_ return; } sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs); - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs); + if (mCallbacksObj) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(attrs); } @@ -111,9 +124,12 @@ static void btavrcp_register_notification_callback(btrc_event_id_t event_id, uin ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification, + if (mCallbacksObj) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification, (jint)event_id, (jint)param); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); } @@ -124,9 +140,13 @@ static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } + if (mCallbacksObj) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, (jint)volume, + (jint)ctype); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, (jint)volume, - (jint)ctype); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); } @@ -137,9 +157,12 @@ static void btavrcp_passthrough_command_callback(int id, int pressed) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } - - sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, (jint)id, - (jint)pressed); + if (mCallbacksObj) { + sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, + (jint)id, (jint)pressed); + } else { + ALOGE("%s: mCallbacksObj is null", __FUNCTION__); + } checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); } diff --git a/jni/com_android_bluetooth_hid.cpp b/jni/com_android_bluetooth_hid.cpp index adff0f58a..adff0f58a 100755..100644 --- a/jni/com_android_bluetooth_hid.cpp +++ b/jni/com_android_bluetooth_hid.cpp diff --git a/jni/com_android_bluetooth_pan.cpp b/jni/com_android_bluetooth_pan.cpp index 500fd91e6..d2b2f6e05 100644 --- a/jni/com_android_bluetooth_pan.cpp +++ b/jni/com_android_bluetooth_pan.cpp @@ -134,14 +134,19 @@ static void initializeNative(JNIEnv *env, jobject object) { return; } + mCallbacksObj = env->NewGlobalRef(object); + bt_status_t status; if ( (status = sPanIf->init(&sBluetoothPanCallbacks)) != BT_STATUS_SUCCESS) { error("Failed to initialize Bluetooth PAN, status: %d", status); sPanIf = NULL; + if (mCallbacksObj != NULL) { + ALOGW("initialization failed: Cleaning up Bluetooth PAN callback object"); + env->DeleteGlobalRef(mCallbacksObj); + mCallbacksObj = NULL; + } return; } - - mCallbacksObj = env->NewGlobalRef(object); } static void cleanupNative(JNIEnv *env, jobject object) { diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java index 7e550a7e2..b86faafbb 100644 --- a/src/com/android/bluetooth/btservice/AdapterProperties.java +++ b/src/com/android/bluetooth/btservice/AdapterProperties.java @@ -604,9 +604,20 @@ class AdapterProperties { } } - private boolean mBluetoothDisabling=false; + private boolean mBluetoothDisabling = false; + + void onBleDisable() { + // Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state. + // When BT disable is invoked, set the scan_mode to NONE + // so no incoming connections are possible + debugLog("onBleDisable"); + if (getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF) { + setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE); + } + } void onBluetoothDisable() { + // From STATE_ON to BLE_ON // When BT disable is invoked, set the scan_mode to NONE // so no incoming connections are possible @@ -618,6 +629,7 @@ class AdapterProperties { setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE); } } + void discoveryStateChangeCallback(int state) { infoLog("Callback:discoveryStateChangeCallback with state:" + state); synchronized (mObject) { diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java index c78adf0b3..f16f082db 100644 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -81,7 +81,7 @@ import android.os.ServiceManager; public class AdapterService extends Service { private static final String TAG = "BluetoothAdapterService"; - private static final boolean DBG = false; + private static final boolean DBG = true; private static final boolean TRACE_REF = true; private static final int MIN_ADVT_INSTANCES_FOR_MA = 5; private static final int MIN_OFFLOADED_FILTERS = 10; @@ -287,6 +287,8 @@ public class AdapterService extends Service { private void processProfileServiceStateChanged(String serviceName, int state) { boolean doUpdate=false; + boolean isBleTurningOn; + boolean isBleTurningOff; boolean isTurningOn; boolean isTurningOff; @@ -307,15 +309,41 @@ public class AdapterService extends Service { synchronized (mAdapterStateMachine) { isTurningOff = mAdapterStateMachine.isTurningOff(); isTurningOn = mAdapterStateMachine.isTurningOn(); + isBleTurningOn = mAdapterStateMachine.isBleTurningOn(); + isBleTurningOff = mAdapterStateMachine.isBleTurningOff(); } - if (isTurningOff) { + debugLog("processProfileServiceStateChanged() - serviceName=" + serviceName + + " isTurningOn=" + isTurningOn + " isTurningOff=" + isTurningOff + + " isBleTurningOn=" + isBleTurningOn + " isBleTurningOff=" + isBleTurningOff); + + if (isBleTurningOn) { + if (serviceName.equals("com.android.bluetooth.gatt.GattService")) { + debugLog("GattService is started"); + mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BLE_STARTED)); + return; + } + + } else if(isBleTurningOff) { + if (serviceName.equals("com.android.bluetooth.gatt.GattService")) { + debugLog("GattService stopped"); + mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BLE_STOPPED)); + return; + } + + } else if (isTurningOff) { + //On to BLE_ON //Process stop or disable pending //Check if all services are stopped if so, do cleanup synchronized (mProfileServicesState) { Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String,Integer> entry = i.next(); + debugLog("Service: " + entry.getKey()); + if (entry.getKey().equals("com.android.bluetooth.gatt.GattService")) { + debugLog("Skip GATT service - already started before"); + continue; + } if (BluetoothAdapter.STATE_OFF != entry.getValue()) { debugLog("onProfileServiceStateChange() - Profile still running: " + entry.getKey()); @@ -326,7 +354,8 @@ public class AdapterService extends Service { debugLog("onProfileServiceStateChange() - All profile services stopped..."); //Send message to state machine mProfilesStarted=false; - mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STOPPED)); + mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STOPPED)); + } else if (isTurningOn) { //Process start pending //Check if all services are started if so, update state @@ -334,6 +363,11 @@ public class AdapterService extends Service { Iterator<Map.Entry<String,Integer>> i = mProfileServicesState.entrySet().iterator(); while (i.hasNext()) { Map.Entry<String,Integer> entry = i.next(); + debugLog("Service: " + entry.getKey()); + if (entry.getKey().equals("com.android.bluetooth.gatt.GattService")) { + debugLog("Skip GATT service - already started before"); + continue; + } if (BluetoothAdapter.STATE_ON != entry.getValue()) { debugLog("onProfileServiceStateChange() - Profile still not running:" + entry.getKey()); @@ -344,7 +378,7 @@ public class AdapterService extends Service { debugLog("onProfileServiceStateChange() - All profile services started."); mProfilesStarted=true; //Send message to state machine - mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED)); + mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } } @@ -387,8 +421,8 @@ public class AdapterService extends Service { debugLog("onDestroy()"); } - void processStart() { - debugLog("processStart()"); + void BleOnProcessStart() { + debugLog("BleOnProcessStart()"); Class[] supportedProfileServices = Config.getSupportedProfiles(); //Initialize data objects for (int i=0; i < supportedProfileServices.length;i++) { @@ -397,7 +431,7 @@ public class AdapterService extends Service { mRemoteDevices = new RemoteDevices(this); mAdapterProperties.init(mRemoteDevices); - debugLog("processStart() - Make Bond State Machine"); + debugLog("BleOnProcessStart() - Make Bond State Machine"); mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices); mJniCallbacks.init(mBondStateMachine,mRemoteDevices); @@ -405,13 +439,22 @@ public class AdapterService extends Service { //FIXME: Set static instance here??? setAdapterService(this); + //Start Gatt service + setGattProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON); + } + + void startCoreServices() + { + debugLog("startCoreServices()"); + Class[] supportedProfileServices = Config.getSupportedProfiles(); + //Start profile services if (!mProfilesStarted && supportedProfileServices.length >0) { //Startup all profile services setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON); }else { - debugLog("processStart() - Profile Services alreay started"); - mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED)); + debugLog("startCoreProfiles(): Profile Services alreay started"); + mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.BREDR_STARTED)); } } @@ -429,6 +472,16 @@ public class AdapterService extends Service { return false; } + boolean stopGattProfileService() { + //TODO: can optimize this instead of looping around all supported profiles + debugLog("stopGattProfileService()"); + Class[] supportedProfileServices = Config.getSupportedProfiles(); + + setGattProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_OFF); + return true; + } + + void updateAdapterState(int prevState, int newState){ if (mCallbacks !=null) { int n=mCallbacks.beginBroadcast(); @@ -517,7 +570,6 @@ public class AdapterService extends Service { mCallbacks.kill(); } - debugLog("cleanup() - Bluetooth process exited normally."); System.exit(0); } @@ -563,6 +615,51 @@ public class AdapterService extends Service { }; @SuppressWarnings("rawtypes") + private void setGattProfileServiceState(Class[] services, int state) { + if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { + Log.w(TAG,"setGattProfileServiceState(): invalid state...Leaving..."); + return; + } + + int expectedCurrentState= BluetoothAdapter.STATE_OFF; + int pendingState = BluetoothAdapter.STATE_TURNING_ON; + + if (state == BluetoothAdapter.STATE_OFF) { + expectedCurrentState= BluetoothAdapter.STATE_ON; + pendingState = BluetoothAdapter.STATE_TURNING_OFF; + } + + for (int i=0; i <services.length;i++) { + String serviceName = services[i].getName(); + String simpleName = services[i].getSimpleName(); + + if (simpleName.equals("GattService")) { + if (DBG) Log.d(TAG, "It is gaTT service"); + Integer serviceState = mProfileServicesState.get(serviceName); + + if(serviceState != null && serviceState != expectedCurrentState) { + debugLog("setProfileServiceState() - Unable to " + + (state == BluetoothAdapter.STATE_OFF ? "start" : "stop" ) + + " service " + serviceName + + ". Invalid state: " + serviceState); + continue; + } + debugLog("setProfileServiceState() - " + + (state == BluetoothAdapter.STATE_OFF ? "Stopping" : "Starting") + + " service " + serviceName); + + mProfileServicesState.put(serviceName,pendingState); + Intent intent = new Intent(this,services[i]); + intent.putExtra(EXTRA_ACTION,ACTION_SERVICE_STATE_CHANGED); + intent.putExtra(BluetoothAdapter.EXTRA_STATE,state); + startService(intent); + return; + } + } + } + + + @SuppressWarnings("rawtypes") private void setProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { debugLog("setProfileServiceState() - Invalid state, leaving..."); @@ -578,6 +675,12 @@ public class AdapterService extends Service { for (int i=0; i <services.length;i++) { String serviceName = services[i].getName(); + String simpleName = services[i].getSimpleName(); + + if (simpleName.equals("GattService")) { + if (DBG) Log.d(TAG, "It is gaTT service. SKIP IT"); + continue; + } Integer serviceState = mProfileServicesState.get(serviceName); if(serviceState != null && serviceState != expectedCurrentState) { debugLog("setProfileServiceState() - Unable to " @@ -1158,54 +1261,56 @@ public class AdapterService extends Service { } return service.dump(); } + + public void onLeServiceUp(){ + AdapterService service = getService(); + if (service == null) return; + service.onLeServiceUp(); + } + + public void onBrEdrDown(){ + AdapterService service = getService(); + if (service == null) return; + service.onBrEdrDown(); + } }; + // ----API Methods-------- - //----API Methods-------- boolean isEnabled() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return mAdapterProperties.getState() == BluetoothAdapter.STATE_ON; - } + } int getState() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - - if (mAdapterProperties == null){ - return BluetoothAdapter.STATE_OFF; - } - else { - debugLog("getState() - mAdapterProperties: " + mAdapterProperties); - return mAdapterProperties.getState(); - } - } + if (mAdapterProperties != null) return mAdapterProperties.getState(); + return BluetoothAdapter.STATE_OFF; + } boolean enable() { return enable (false); - } + } public boolean enableNoAutoConnect() { return enable (true); } public synchronized boolean enable(boolean quietMode) { - enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permission"); + enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); + debugLog("enable() - Enable called with quiet mode status = " + mQuietmode); - mQuietmode = quietMode; - Message m = - mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); + mQuietmode = quietMode; + Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON); mAdapterStateMachine.sendMessage(m); return true; } boolean disable() { - enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, - "Need BLUETOOTH ADMIN permission"); + enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); debugLog("disable() called..."); - Message m = - mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); + Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_OFF); mAdapterStateMachine.sendMessage(m); return true; } @@ -1755,6 +1860,16 @@ public class AdapterService extends Service { return sb.toString(); } + public void onLeServiceUp() { + Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON); + mAdapterStateMachine.sendMessage(m); + } + + public void onBrEdrDown() { + Message m = mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_OFF); + mAdapterStateMachine.sendMessage(m); + } + private static int convertScanModeToHal(int mode) { switch (mode) { case BluetoothAdapter.SCAN_MODE_NONE: @@ -1888,11 +2003,11 @@ public class AdapterService extends Service { } private void debugLog(String msg) { - if (DBG) Log.d(TAG +"(" +hashCode()+")", msg); + if (DBG) Log.d(TAG, msg); } private void errorLog(String msg) { - Log.e(TAG +"(" +hashCode()+")", msg); + Log.e(TAG, msg); } private final BroadcastReceiver mAlarmBroadcastReceiver = new BroadcastReceiver() { diff --git a/src/com/android/bluetooth/btservice/AdapterState.java b/src/com/android/bluetooth/btservice/AdapterState.java index 5f9c30bf4..38db5dbed 100755..100644 --- a/src/com/android/bluetooth/btservice/AdapterState.java +++ b/src/com/android/bluetooth/btservice/AdapterState.java @@ -37,55 +37,79 @@ import com.android.internal.util.StateMachine; final class AdapterState extends StateMachine { private static final boolean DBG = true; - private static final boolean VDBG = false; + private static final boolean VDBG = true; private static final String TAG = "BluetoothAdapterState"; + static final int BLE_TURN_ON = 0; static final int USER_TURN_ON = 1; - static final int STARTED=2; + static final int BREDR_STARTED=2; static final int ENABLED_READY = 3; + static final int BLE_STARTED=4; static final int USER_TURN_OFF = 20; static final int BEGIN_DISABLE = 21; static final int ALL_DEVICES_DISCONNECTED = 22; + static final int BLE_TURN_OFF = 23; static final int DISABLED = 24; - static final int STOPPED=25; + static final int BLE_STOPPED=25; + static final int BREDR_STOPPED = 26; - static final int START_TIMEOUT = 100; + static final int BREDR_START_TIMEOUT = 100; static final int ENABLE_TIMEOUT = 101; static final int DISABLE_TIMEOUT = 103; - static final int STOP_TIMEOUT = 104; + static final int BLE_STOP_TIMEOUT = 104; static final int SET_SCAN_MODE_TIMEOUT = 105; + static final int BLE_START_TIMEOUT = 106; + static final int BREDR_STOP_TIMEOUT = 107; static final int USER_TURN_OFF_DELAY_MS=500; //TODO: tune me - private static final int ENABLE_TIMEOUT_DELAY = 8000; + private static final int ENABLE_TIMEOUT_DELAY = 12000; private static final int DISABLE_TIMEOUT_DELAY = 8000; - private static final int START_TIMEOUT_DELAY = 5000; - private static final int STOP_TIMEOUT_DELAY = 5000; + private static final int BREDR_START_TIMEOUT_DELAY = 4000; + //BLE_START_TIMEOUT can happen quickly as it just a start gattservice + private static final int BLE_START_TIMEOUT_DELAY = 2000; //To start GattService + private static final int BLE_STOP_TIMEOUT_DELAY = 2000; + //BREDR_STOP_TIMEOUT can < STOP_TIMEOUT + private static final int BREDR_STOP_TIMEOUT_DELAY = 4000; private static final int PROPERTY_OP_DELAY =2000; private AdapterService mAdapterService; private AdapterProperties mAdapterProperties; private PendingCommandState mPendingCommandState = new PendingCommandState(); private OnState mOnState = new OnState(); private OffState mOffState = new OffState(); + private BleOnState mBleOnState = new BleOnState(); public boolean isTurningOn() { boolean isTurningOn= mPendingCommandState.isTurningOn(); - if (VDBG) Log.d(TAG,"isTurningOn()=" + isTurningOn); + verboseLog("isTurningOn()=" + isTurningOn); return isTurningOn; } + public boolean isBleTurningOn() { + boolean isBleTurningOn= mPendingCommandState.isBleTurningOn(); + verboseLog("isBleTurningOn()=" + isBleTurningOn); + return isBleTurningOn; + } + + public boolean isBleTurningOff() { + boolean isBleTurningOff = mPendingCommandState.isBleTurningOff(); + verboseLog("isBleTurningOff()=" + isBleTurningOff); + return isBleTurningOff; + } + public boolean isTurningOff() { boolean isTurningOff= mPendingCommandState.isTurningOff(); - if (VDBG) Log.d(TAG,"isTurningOff()=" + isTurningOff); + verboseLog("isTurningOff()=" + isTurningOff); return isTurningOff; } private AdapterState(AdapterService service, AdapterProperties adapterProperties) { super("BluetoothAdapterState:"); addState(mOnState); + addState(mBleOnState); addState(mOffState); addState(mPendingCommandState); mAdapterService = service; @@ -94,7 +118,7 @@ final class AdapterState extends StateMachine { } public static AdapterState make(AdapterService service, AdapterProperties adapterProperties) { - Log.d(TAG, "make"); + Log.d(TAG, "make() - Creating AdapterState"); AdapterState as = new AdapterState(service, adapterProperties); as.start(); return as; @@ -121,25 +145,76 @@ final class AdapterState extends StateMachine { public boolean processMessage(Message msg) { AdapterService adapterService = mAdapterService; if (adapterService == null) { - Log.e(TAG,"receive message at OffState after cleanup:" + - msg.what); + errorLog("Received message in OffState after cleanup: " + msg.what); return false; } + + debugLog("Current state: OFF, message: " + msg.what); + + switch(msg.what) { + case BLE_TURN_ON: + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON); + mPendingCommandState.setBleTurningOn(true); + transitionTo(mPendingCommandState); + sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY); + adapterService.BleOnProcessStart(); + break; + + case USER_TURN_OFF: + //TODO: Handle case of service started and stopped without enable + break; + + default: + return false; + } + return true; + } + } + + private class BleOnState extends State { + @Override + public void enter() { + infoLog("Entering BleOnState"); + } + + @Override + public boolean processMessage(Message msg) { + + AdapterService adapterService = mAdapterService; + AdapterProperties adapterProperties = mAdapterProperties; + if ((adapterService == null) || (adapterProperties == null)) { + errorLog("Received message in BleOnState after cleanup: " + msg.what); + return false; + } + + debugLog("Current state: BLE ON, message: " + msg.what); + switch(msg.what) { case USER_TURN_ON: - if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_ON"); notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON); mPendingCommandState.setTurningOn(true); transitionTo(mPendingCommandState); - sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY); - adapterService.processStart(); + sendMessageDelayed(BREDR_START_TIMEOUT, BREDR_START_TIMEOUT_DELAY); + adapterService.startCoreServices(); break; + case USER_TURN_OFF: - if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_OFF"); - //TODO: Handle case of service started and stopped without enable + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF); + mPendingCommandState.setBleTurningOff(true); + adapterProperties.onBleDisable(); + transitionTo(mPendingCommandState); + sendMessageDelayed(DISABLE_TIMEOUT, DISABLE_TIMEOUT_DELAY); + boolean ret = adapterService.disableNative(); + if (!ret) { + removeMessages(DISABLE_TIMEOUT); + errorLog("Error while calling disableNative"); + //FIXME: what about post enable services + mPendingCommandState.setBleTurningOff(false); + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); + } break; + default: - if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=OFF, MESSAGE = " + msg.what ); return false; } return true; @@ -149,10 +224,11 @@ final class AdapterState extends StateMachine { private class OnState extends State { @Override public void enter() { - infoLog("Entering On State"); + infoLog("Entering OnState"); + AdapterService adapterService = mAdapterService; if (adapterService == null) { - Log.e(TAG,"enter OnState after cleanup"); + errorLog("Entered OnState after cleanup"); return; } adapterService.autoConnect(); @@ -162,14 +238,14 @@ final class AdapterState extends StateMachine { public boolean processMessage(Message msg) { AdapterProperties adapterProperties = mAdapterProperties; if (adapterProperties == null) { - Log.e(TAG,"receive message at OnState after cleanup:" + - msg.what); + errorLog("Received message in OnState after cleanup: " + msg.what); return false; } + debugLog("Current state: ON, message: " + msg.what); + switch(msg.what) { - case USER_TURN_OFF: - if (DBG) Log.d(TAG,"CURRENT_STATE=ON, MESSAGE = USER_TURN_OFF"); + case BLE_TURN_OFF: notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_OFF); mPendingCommandState.setTurningOff(true); transitionTo(mPendingCommandState); @@ -182,11 +258,9 @@ final class AdapterState extends StateMachine { break; case USER_TURN_ON: - if (DBG) Log.d(TAG,"CURRENT_STATE=ON, MESSAGE = USER_TURN_ON"); - Log.i(TAG,"Bluetooth already ON, ignoring USER_TURN_ON"); break; + default: - if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=ON, MESSAGE = " + msg.what ); return false; } return true; @@ -196,9 +270,11 @@ final class AdapterState extends StateMachine { private class PendingCommandState extends State { private boolean mIsTurningOn; private boolean mIsTurningOff; + private boolean mIsBleTurningOn; + private boolean mIsBleTurningOff; public void enter() { - infoLog("Entering PendingCommandState State: isTurningOn()=" + isTurningOn() + ", isTurningOff()=" + isTurningOff()); + infoLog("Entering PendingCommandState"); } public void setTurningOn(boolean isTurningOn) { @@ -217,89 +293,111 @@ final class AdapterState extends StateMachine { return mIsTurningOff; } + public void setBleTurningOn(boolean isBleTurningOn) { + mIsBleTurningOn = isBleTurningOn; + } + + public boolean isBleTurningOn() { + return mIsBleTurningOn; + } + + public void setBleTurningOff(boolean isBleTurningOff) { + mIsBleTurningOff = isBleTurningOff; + } + + public boolean isBleTurningOff() { + return mIsBleTurningOff; + } + @Override public boolean processMessage(Message msg) { boolean isTurningOn= isTurningOn(); boolean isTurningOff = isTurningOff(); + boolean isBleTurningOn = isBleTurningOn(); + boolean isBleTurningOff = isBleTurningOff(); AdapterService adapterService = mAdapterService; AdapterProperties adapterProperties = mAdapterProperties; if ((adapterService == null) || (adapterProperties == null)) { - Log.e(TAG,"receive message at Pending State after cleanup:" + - msg.what); + errorLog("Received message in PendingCommandState after cleanup: " + msg.what); return false; } + debugLog("Current state: PENDING_COMMAND, message: " + msg.what); + switch (msg.what) { case USER_TURN_ON: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = USER_TURN_ON" - + ", isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - if (isTurningOn) { - Log.i(TAG,"CURRENT_STATE=PENDING: Alreadying turning on bluetooth... Ignoring USER_TURN_ON..."); - } else { - Log.i(TAG,"CURRENT_STATE=PENDING: Deferring request USER_TURN_ON"); + if (isBleTurningOff || isTurningOff) { //TODO:do we need to send it after ble turn off also?? + infoLog("Deferring USER_TURN_ON request..."); deferMessage(msg); } break; + case USER_TURN_OFF: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = USER_TURN_ON" - + ", isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - if (isTurningOff) { - Log.i(TAG,"CURRENT_STATE=PENDING: Alreadying turning off bluetooth... Ignoring USER_TURN_OFF..."); - } else { - Log.i(TAG,"CURRENT_STATE=PENDING: Deferring request USER_TURN_OFF"); + if (isTurningOn || isBleTurningOn) { + infoLog("Deferring USER_TURN_OFF request..."); + deferMessage(msg); + } + break; + + case BLE_TURN_ON: + if (isTurningOff || isBleTurningOff) { + infoLog("Deferring BLE_TURN_ON request..."); + deferMessage(msg); + } + break; + + case BLE_TURN_OFF: + if (isTurningOn || isBleTurningOn) { + infoLog("Deferring BLE_TURN_OFF request..."); deferMessage(msg); } break; - case STARTED: { - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STARTED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); + + case BLE_STARTED: //Remove start timeout - removeMessages(START_TIMEOUT); + removeMessages(BLE_START_TIMEOUT); //Enable - boolean ret = adapterService.enableNative(); - if (!ret) { - Log.e(TAG, "Error while turning Bluetooth On"); + if (!adapterService.enableNative()) { + errorLog("Error while turning Bluetooth on"); notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); transitionTo(mOffState); } else { sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY); } - } break; - case ENABLED_READY: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = ENABLE_READY, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - removeMessages(ENABLE_TIMEOUT); + case BREDR_STARTED: + //Remove start timeout + removeMessages(BREDR_START_TIMEOUT); adapterProperties.onBluetoothReady(); mPendingCommandState.setTurningOn(false); transitionTo(mOnState); notifyAdapterStateChange(BluetoothAdapter.STATE_ON); break; + case ENABLED_READY: + removeMessages(ENABLE_TIMEOUT); + mPendingCommandState.setBleTurningOn(false); + transitionTo(mBleOnState); + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); + break; + case SET_SCAN_MODE_TIMEOUT: - Log.w(TAG,"Timeout will setting scan mode..Continuing with disable..."); + warningLog("Timeout while setting scan mode. Continuing with disable..."); //Fall through - case BEGIN_DISABLE: { - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = BEGIN_DISABLE, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); + case BEGIN_DISABLE: removeMessages(SET_SCAN_MODE_TIMEOUT); - sendMessageDelayed(DISABLE_TIMEOUT, DISABLE_TIMEOUT_DELAY); - boolean ret = adapterService.disableNative(); - if (!ret) { - removeMessages(DISABLE_TIMEOUT); - Log.e(TAG, "Error while turning Bluetooth Off"); - //FIXME: what about post enable services - mPendingCommandState.setTurningOff(false); - notifyAdapterStateChange(BluetoothAdapter.STATE_ON); - } - } + sendMessageDelayed(BREDR_STOP_TIMEOUT, BREDR_STOP_TIMEOUT_DELAY); + adapterService.stopProfileServices(); break; + case DISABLED: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = DISABLED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); if (isTurningOn) { removeMessages(ENABLE_TIMEOUT); - errorLog("Error enabling Bluetooth - hardware init failed"); + errorLog("Error enabling Bluetooth - hardware init failed?"); mPendingCommandState.setTurningOn(false); transitionTo(mOffState); adapterService.stopProfileServices(); @@ -307,60 +405,80 @@ final class AdapterState extends StateMachine { break; } removeMessages(DISABLE_TIMEOUT); - sendMessageDelayed(STOP_TIMEOUT, STOP_TIMEOUT_DELAY); - if (adapterService.stopProfileServices()) { - Log.d(TAG,"Stopping profile services that were post enabled"); + sendMessageDelayed(BLE_STOP_TIMEOUT, BLE_STOP_TIMEOUT_DELAY); + if (adapterService.stopGattProfileService()) { + debugLog("Stopping Gatt profile services that were post enabled"); break; } //Fall through if no services or services already stopped - case STOPPED: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STOPPED, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - removeMessages(STOP_TIMEOUT); - setTurningOff(false); + case BLE_STOPPED: + removeMessages(BLE_STOP_TIMEOUT); + setBleTurningOff(false); transitionTo(mOffState); notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); break; - case START_TIMEOUT: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = START_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - errorLog("Error enabling Bluetooth"); - mPendingCommandState.setTurningOn(false); + + case BREDR_STOPPED: + removeMessages(BREDR_STOP_TIMEOUT); + setTurningOff(false); + transitionTo(mBleOnState); + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); + break; + + case BLE_START_TIMEOUT: + errorLog("Error enabling Bluetooth (BLE start timeout)"); + mPendingCommandState.setBleTurningOn(false); transitionTo(mOffState); notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); break; - case ENABLE_TIMEOUT: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = ENABLE_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - errorLog("Error enabling Bluetooth"); + + case BREDR_START_TIMEOUT: + errorLog("Error enabling Bluetooth (start timeout)"); mPendingCommandState.setTurningOn(false); + transitionTo(mBleOnState); + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); + break; + + case ENABLE_TIMEOUT: + errorLog("Error enabling Bluetooth (enable timeout)"); + mPendingCommandState.setBleTurningOn(false); transitionTo(mOffState); notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); break; - case STOP_TIMEOUT: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = STOP_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - errorLog("Error stopping Bluetooth profiles"); + + case BREDR_STOP_TIMEOUT: + errorLog("Error stopping Bluetooth profiles (stop timeout)"); + mPendingCommandState.setTurningOff(false); + transitionTo(mBleOnState); + notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_ON); + break; + + case BLE_STOP_TIMEOUT: + errorLog("Error stopping Bluetooth profiles (BLE stop timeout)"); mPendingCommandState.setTurningOff(false); transitionTo(mOffState); + notifyAdapterStateChange(BluetoothAdapter.STATE_OFF); break; + case DISABLE_TIMEOUT: - if (DBG) Log.d(TAG,"CURRENT_STATE=PENDING, MESSAGE = DISABLE_TIMEOUT, isTurningOn=" + isTurningOn + ", isTurningOff=" + isTurningOff); - errorLog("Error disabling Bluetooth"); + errorLog("Error disabling Bluetooth (disable timeout)"); mPendingCommandState.setTurningOff(false); transitionTo(mOnState); notifyAdapterStateChange(BluetoothAdapter.STATE_ON); break; + default: - if (DBG) Log.d(TAG,"ERROR: UNEXPECTED MESSAGE: CURRENT_STATE=PENDING, MESSAGE = " + msg.what ); return false; } return true; } } - private void notifyAdapterStateChange(int newState) { AdapterService adapterService = mAdapterService; AdapterProperties adapterProperties = mAdapterProperties; if ((adapterService == null) || (adapterProperties == null)) { - Log.e(TAG,"notifyAdapterStateChange after cleanup:" + newState); + errorLog("notifyAdapterStateChange after cleanup:" + newState); return; } @@ -373,9 +491,11 @@ final class AdapterState extends StateMachine { void stateChangeCallback(int status) { if (status == AbstractionLayer.BT_STATE_OFF) { sendMessage(DISABLED); + } else if (status == AbstractionLayer.BT_STATE_ON) { // We should have got the property change for adapter and remote devices. sendMessage(ENABLED_READY); + } else { errorLog("Incorrect status in stateChangeCallback"); } @@ -385,6 +505,18 @@ final class AdapterState extends StateMachine { if (DBG) Log.i(TAG, msg); } + private void debugLog(String msg) { + if (DBG) Log.d(TAG, msg); + } + + private void warningLog(String msg) { + if (DBG) Log.d(TAG, msg); + } + + private void verboseLog(String msg) { + if (VDBG) Log.v(TAG, msg); + } + private void errorLog(String msg) { Log.e(TAG, msg); } diff --git a/src/com/android/bluetooth/btservice/ProfileService.java b/src/com/android/bluetooth/btservice/ProfileService.java index 1b70944ae..1e332bb69 100644 --- a/src/com/android/bluetooth/btservice/ProfileService.java +++ b/src/com/android/bluetooth/btservice/ProfileService.java @@ -231,7 +231,10 @@ public abstract class ProfileService extends Service { } protected BluetoothDevice getDevice(byte[] address) { - return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); + if(mAdapter != null){ + return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); + } + return null; } protected void log(String msg) { diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java index e49b48632..3a9fd1c64 100644 --- a/src/com/android/bluetooth/btservice/RemoteDevices.java +++ b/src/com/android/bluetooth/btservice/RemoteDevices.java @@ -323,6 +323,8 @@ final class RemoteDevices { errorLog("aclStateChangeCallback: Device is NULL"); return; } + int state = mAdapterService.getState(); + Log.e(TAG, "state" + state + "newState" + newState); DeviceProperties prop = getDeviceProperties(device); if (prop == null) { @@ -330,10 +332,24 @@ final class RemoteDevices { } Intent intent = null; if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { - intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); + if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { + intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); + } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { + intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); + } debugLog("aclStateChangeCallback: State:Connected to Device:" + device); } else { - intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); + if (device.getBondState() == BluetoothDevice.BOND_BONDING) { + /*Broadcasting PAIRING_CANCEL intent as well in this case*/ + intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); + } + if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { + intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); + } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { + intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); + } debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device); } intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); diff --git a/src/com/android/bluetooth/gatt/ContextMap.java b/src/com/android/bluetooth/gatt/ContextMap.java index 1b40bc0d8..f492237b2 100644 --- a/src/com/android/bluetooth/gatt/ContextMap.java +++ b/src/com/android/bluetooth/gatt/ContextMap.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.UUID; +import java.util.HashMap; +import java.util.Map; /** * Helper class that keeps track of registered GATT applications. @@ -306,6 +308,17 @@ import java.util.UUID; } /** + * Returns connect device map with addr and appid + */ + Map<Integer, String> getConnectedMap(){ + Map<Integer, String> connectedmap = new HashMap<Integer, String>(); + for(Connection conn: mConnections){ + connectedmap.put(conn.appId, conn.address); + } + return connectedmap; + } + + /** * Logs debug information. */ void dump(StringBuilder sb) { diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java index fbeaad3ab..04c9da5b0 100644 --- a/src/com/android/bluetooth/gatt/GattService.java +++ b/src/com/android/bluetooth/gatt/GattService.java @@ -546,6 +546,20 @@ public class GattService extends ProfileService { if (service == null) return; service.stopMultiAdvertising(new AdvertiseClient(clientIf)); } + + @Override + public void disconnectAll() { + GattService service = getService(); + if (service == null) return; + service.disconnectAll(); + } + + @Override + public void unregAll() { + GattService service = getService(); + if (service == null) return; + service.unregAll(); + } }; /************************************************************************** @@ -1333,6 +1347,23 @@ public class GattService extends ProfileService { mScanManager.stopScan(client); } + void disconnectAll() { + if (DBG) Log.d(TAG, "disconnectAll()"); + Map<Integer, String> connMap = mClientMap.getConnectedMap(); + for(Map.Entry<Integer, String> entry:connMap.entrySet()){ + if (DBG) Log.d(TAG, "disconnecting addr:" + entry.getValue()); + clientDisconnect(entry.getKey(), entry.getValue()); + //clientDisconnect(int clientIf, String address) + } + } + + void unregAll() { + for(ClientMap.App app:mClientMap.mApps){ + if (DBG) Log.d(TAG, "unreg:" + app.id); + unregisterClient(app.id); + } + } + /************************************************************************** * GATT Service functions - CLIENT *************************************************************************/ diff --git a/src/com/android/bluetooth/hid/HidService.java b/src/com/android/bluetooth/hid/HidService.java index 418c13b7d..be769fc80 100755 --- a/src/com/android/bluetooth/hid/HidService.java +++ b/src/com/android/bluetooth/hid/HidService.java @@ -47,7 +47,7 @@ import java.util.Map; * @hide */ public class HidService extends ProfileService { - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String TAG = "HidService"; private Map<BluetoothDevice, Integer> mInputDevices; |