b/2498180 b/2568119 Retry if BT dock disconnects unexpectedly
Change-Id: Ic4771e7c305192fee56f5f80c6cabeecf11a99dc
This commit is contained in:
@@ -614,6 +614,8 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.DOCK_EVENT" />
|
<action android:name="android.intent.action.DOCK_EVENT" />
|
||||||
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
||||||
|
<action android:name="android.bluetooth.headset.action.STATE_CHANGED" />
|
||||||
|
<action android:name="android.bluetooth.a2dp.action.SINK_STATE_CHANGED" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
@@ -16,12 +16,17 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
|
||||||
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.bluetooth.BluetoothA2dp;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothHeadset;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -75,6 +80,54 @@ public class DockEventReceiver extends BroadcastReceiver {
|
|||||||
if (DEBUG) Log.e(TAG, "Unknown state");
|
if (DEBUG) Log.e(TAG, "Unknown state");
|
||||||
break;
|
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())) {
|
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
|
||||||
int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
|
int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
|
||||||
if (btState != BluetoothAdapter.STATE_TURNING_ON) {
|
if (btState != BluetoothAdapter.STATE_TURNING_ON) {
|
||||||
|
@@ -87,6 +87,15 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
private static final String SHARED_PREFERENCES_KEY_DISABLE_BT =
|
private static final String SHARED_PREFERENCES_KEY_DISABLE_BT =
|
||||||
"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;
|
private static final int INVALID_STARTID = -100;
|
||||||
|
|
||||||
// Created in OnCreate()
|
// Created in OnCreate()
|
||||||
@@ -161,6 +170,32 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
return START_NOT_STICKY;
|
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);
|
Message msg = parseIntent(intent);
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
// Bad intent
|
// Bad intent
|
||||||
@@ -169,6 +204,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg.what == MSG_TYPE_DOCKED) {
|
||||||
|
removeSetting(SHARED_PREFERENCES_KEY_CONNECT_RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
msg.arg2 = startId;
|
msg.arg2 = startId;
|
||||||
processMessage(msg);
|
processMessage(msg);
|
||||||
|
|
||||||
@@ -248,10 +287,10 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "DISABLE_BT_WHEN_UNDOCKED = "
|
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
|
// BT was disabled when we first docked
|
||||||
if (!hasOtherConnectedDevices(device)) {
|
if (!hasOtherConnectedDevices(device)) {
|
||||||
if(DEBUG) Log.d(TAG, "QUEUED BT DISABLE");
|
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);
|
removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT_WHEN_UNDOCKED);
|
||||||
} else {
|
} else {
|
||||||
// disable() returned an error. Persist a flag to disable BT later
|
// 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;
|
mPendingTurnOffStartId = startId;
|
||||||
deferFinishCall = true;
|
deferFinishCall = true;
|
||||||
if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId);
|
if(DEBUG) Log.d(TAG, "disable failed. try again later " + startId);
|
||||||
@@ -509,7 +548,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
} else {
|
} else {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "A DISABLE_BT_WHEN_UNDOCKED = "
|
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.
|
// Reconnect if docked and bluetooth was enabled by user.
|
||||||
Intent i = registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
|
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) {
|
if (device != null) {
|
||||||
connectIfEnabled(device);
|
connectIfEnabled(device);
|
||||||
}
|
}
|
||||||
} else if (getSetting(SHARED_PREFERENCES_KEY_DISABLE_BT)
|
} else if (getSettingBool(SHARED_PREFERENCES_KEY_DISABLE_BT)
|
||||||
&& mBtManager.getBluetoothAdapter().disable()) {
|
&& mBtManager.getBluetoothAdapter().disable()) {
|
||||||
mPendingTurnOffStartId = startId;
|
mPendingTurnOffStartId = startId;
|
||||||
removeSetting(SHARED_PREFERENCES_KEY_DISABLE_BT);
|
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) {
|
private synchronized void connectIfEnabled(BluetoothDevice device) {
|
||||||
CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device);
|
CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(mContext, mBtManager, device);
|
||||||
List<Profile> profiles = cachedDevice.getConnectableProfiles();
|
List<Profile> profiles = cachedDevice.getConnectableProfiles();
|
||||||
@@ -612,7 +679,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
mPendingDevice = device;
|
mPendingDevice = device;
|
||||||
mPendingStartId = startId;
|
mPendingStartId = startId;
|
||||||
if (btState != BluetoothAdapter.STATE_TURNING_ON) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -676,16 +744,29 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
|
|||||||
return cachedBluetoothDevice;
|
return cachedBluetoothDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean getSetting(String key) {
|
private boolean getSettingBool(String key) {
|
||||||
SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
|
SharedPreferences sharedPref = getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||||
Context.MODE_PRIVATE);
|
Context.MODE_PRIVATE);
|
||||||
return sharedPref.getBoolean(key, false);
|
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,
|
SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||||
Context.MODE_PRIVATE).edit();
|
Context.MODE_PRIVATE).edit();
|
||||||
editor.putBoolean(key, disableBt);
|
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.putInt(key, value);
|
||||||
editor.commit();
|
editor.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user