From: Michael Chan Date: Tue, 6 Apr 2010 21:49:30 +0000 (-0700) Subject: b/2498180 b/2568119 Retry if BT dock disconnects unexpectedly X-Git-Tag: android-x86-2.2~56^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=732c1dad5a4871597652f17986b7a602897e5a76;p=android-x86%2Fpackages-apps-Settings.git b/2498180 b/2568119 Retry if BT dock disconnects unexpectedly Change-Id: Ic4771e7c305192fee56f5f80c6cabeecf11a99dc --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 97fbaecfbf..3499a42f8d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -466,7 +466,7 @@ - + @@ -614,6 +614,8 @@ + + diff --git a/src/com/android/settings/bluetooth/DockEventReceiver.java b/src/com/android/settings/bluetooth/DockEventReceiver.java index 2d634b2e45..6d119722ac 100644 --- a/src/com/android/settings/bluetooth/DockEventReceiver.java +++ b/src/com/android/settings/bluetooth/DockEventReceiver.java @@ -16,12 +16,17 @@ package com.android.settings.bluetooth; +import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; + import android.app.Service; +import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadset; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.PowerManager; import android.util.Log; @@ -75,6 +80,54 @@ public class DockEventReceiver extends BroadcastReceiver { if (DEBUG) Log.e(TAG, "Unknown state"); break; } + } else if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) { + /* + * Reconnect to the dock if: + * 1) it is a dock + * 2) it is disconnected + * 3) the disconnect is initiated remotely + * 4) the dock is still docked (check can only be done in the Service) + */ + if (device == null) { + if (DEBUG) Log.d(TAG, "Device is missing"); + return; + } + + int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, + BluetoothHeadset.STATE_CONNECTED); + if (newState != BluetoothHeadset.STATE_DISCONNECTED) return; + + int source = intent.getIntExtra(BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR, + BluetoothHeadset.LOCAL_DISCONNECT); + if (source != BluetoothHeadset.REMOTE_DISCONNECT) return; + + // Too bad, the dock state can't be checked from a BroadcastReceiver. + Intent i = new Intent(intent); + i.setClass(context, DockService.class); + beginStartingService(context, i); + + } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) { + /* + * Reconnect to the dock if: + * 1) it is a dock + * 2) it is an unexpected disconnect i.e. didn't go through disconnecting state + * 3) the dock is still docked (check can only be done in the Service) + */ + if (device == null) { + if (DEBUG) Log.d(TAG, "Device is missing"); + return; + } + + int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0); + int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0); + if (newState == BluetoothA2dp.STATE_DISCONNECTED && + oldState != BluetoothA2dp.STATE_DISCONNECTING) { + // Too bad, the dock state can't be checked from a BroadcastReceiver. + Intent i = new Intent(intent); + i.setClass(context, DockService.class); + beginStartingService(context, i); + } + } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if (btState != BluetoothAdapter.STATE_TURNING_ON) { diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java index 1425e23256..f318987bc8 100644 --- a/src/com/android/settings/bluetooth/DockService.java +++ b/src/com/android/settings/bluetooth/DockService.java @@ -87,6 +87,15 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli private static final String SHARED_PREFERENCES_KEY_DISABLE_BT = "disable_bt"; + private static final String SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT = + "connect_retry_count"; + + /* + * If disconnected unexpectedly, reconnect up to 6 times. Each profile counts + * as one time so it's only 3 times for both profiles on the car dock. + */ + private static final int MAX_CONNECT_RETRY = 6; + private static final int INVALID_STARTID = -100; // Created in OnCreate() @@ -161,6 +170,32 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli return START_NOT_STICKY; } + /* + * This assumes that the intent sender has checked that this is a dock + * and that the intent is for a disconnect + */ + if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) { + BluetoothDevice disconnectedDevice = intent + .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + + int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0); + if (retryCount < MAX_CONNECT_RETRY) { + setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1); + handleUnexpectedDisconnect(disconnectedDevice, Profile.HEADSET, startId); + } + return START_NOT_STICKY; + } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) { + BluetoothDevice disconnectedDevice = intent + .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + + int retryCount = getSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, 0); + if (retryCount < MAX_CONNECT_RETRY) { + setSettingInt(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT, retryCount + 1); + handleUnexpectedDisconnect(disconnectedDevice, Profile.A2DP, startId); + } + return START_NOT_STICKY; + } + Message msg = parseIntent(intent); if (msg == null) { // Bad intent @@ -169,6 +204,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli return START_NOT_STICKY; } + if (msg.what == MSG_TYPE_DOCKED) { + removeSetting(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT); + } + msg.arg2 = startId; processMessage(msg); @@ -248,10 +287,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli if (DEBUG) { Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = " - + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); + + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); } - if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) { + if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)) { // BT was disabled when we first docked if (!hasOtherConnectedDevices(device)) { if(DEBUG) Log.d(TAG, "QUEUED BT DISABLE"); @@ -280,7 +319,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED); } else { // disable() returned an error. Persist a flag to disable BT later - setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT, true); + setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT, true); mPendingTurnOffStartId = startId; deferFinishCall = true; if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId); @@ -509,7 +548,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli } else { if (DEBUG) { Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = " - + getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); + + getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED)); } // Reconnect if docked and bluetooth was enabled by user. Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); @@ -522,7 +561,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli if (device != null) { connectIfEnabled(device); } - } else if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT) + } else if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT) && mBtManager.getBluetoothAdapter().disable()) { mPendingTurnOffStartId = startId; removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT); @@ -565,6 +604,34 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli } } + private void handleUnexpectedDisconnect(BluetoothDevice disconnectedDevice, Profile profile, + int startId) { + synchronized (this) { + if (DEBUG) Log.d(TAG, "handling failed connect for " + disconnectedDevice); + + // Reconnect if docked. + if (disconnectedDevice != null) { + // registerReceiver can't be called from a BroadcastReceiver + Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + if (i != null) { + int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { + BluetoothDevice dockedDevice = i + .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (dockedDevice != null && dockedDevice.equals(disconnectedDevice)) { + CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, + mBtManager, dockedDevice); + cachedDevice.connect(profile); + } + } + } + } + + DockEventReceiver.finishStartingService(this, startId); + } + } + private synchronized void connectIfEnabled(BluetoothDevice device) { CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device); List profiles = cachedDevice.getConnectableProfiles(); @@ -612,7 +679,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli mPendingDevice = device; mPendingStartId = startId; if (btState != BluetoothAdapter.STATE_TURNING_ON) { - setSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED, true); + setSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED, + true); } return; } @@ -676,16 +744,29 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli return cachedBluetoothDevice; } - private boolean getSetting(String key) { + private boolean getSettingBool(String key) { SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); return sharedPref.getBoolean(key, false); } - private void setSetting(String key, boolean disableBt) { + private int getSettingInt(String key, int defaultValue) { + SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME, + Context.MODE_PRIVATE); + return sharedPref.getInt(key, defaultValue); + } + + private void setSettingBool(String key, boolean bool) { + SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME, + Context.MODE_PRIVATE).edit(); + editor.putBoolean(key, bool); + editor.commit(); + } + + private void setSettingInt(String key, int value) { SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE).edit(); - editor.putBoolean(key, disableBt); + editor.putInt(key, value); editor.commit(); }