Merge "b/2680057 Fixed a bug where bt won't connect when the phone is docked (if Settings wasn't running)." into kraken

This commit is contained in:
Michael Chan
2010-05-27 17:11:24 -07:00
committed by Android (Google) Code Review
2 changed files with 125 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.ServiceListener;
import android.app.AlertDialog;
import android.app.Notification;
@@ -48,7 +49,7 @@ import java.util.Set;
public class DockService extends Service implements AlertDialog.OnMultiChoiceClickListener,
DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
CompoundButton.OnCheckedChangeListener {
CompoundButton.OnCheckedChangeListener, ServiceListener {
private static final String TAG = "DockService";
@@ -101,6 +102,7 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
// Created in OnCreate()
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private Runnable mRunnable;
private DockService mContext;
private LocalBluetoothManager mBtManager;
@@ -138,6 +140,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
mRunnable = null;
LocalBluetoothProfileManager.removeServiceListener(this);
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
@@ -228,8 +232,8 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
// This method gets messages from both onStartCommand and mServiceHandler/mServiceLooper
private synchronized void processMessage(Message msg) {
int msgType = msg.what;
int state = msg.arg1;
int startId = msg.arg2;
final int state = msg.arg1;
final int startId = msg.arg2;
boolean deferFinishCall = false;
BluetoothDevice device = null;
if (msg.obj != null) {
@@ -271,12 +275,23 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
mDevice = device;
if (mBtManager.getDockAutoConnectSetting(device.getAddress())) {
// Setting == auto connect
initBtSettings(mContext, device, state, false);
applyBtSettings(mDevice, startId);
// Register first in case LocalBluetoothProfileManager
// becomes ready after isManagerReady is called and it
// would be too late to register a service listener.
LocalBluetoothProfileManager.addServiceListener(this);
if (LocalBluetoothProfileManager.isManagerReady()) {
handleDocked(device, state, startId);
// Not needed after all
LocalBluetoothProfileManager.removeServiceListener(this);
} else {
createDialog(mContext, mDevice, state, startId);
final BluetoothDevice d = device;
mRunnable = new Runnable() {
public void run() {
handleDocked(d, state, startId);
}
};
deferFinishCall = true;
}
}
break;
@@ -721,8 +736,21 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
}
}
private synchronized void handleDocked(final BluetoothDevice device, final int state,
final int startId) {
if (mBtManager.getDockAutoConnectSetting(device.getAddress())) {
// Setting == auto connect
initBtSettings(mContext, device, state, false);
applyBtSettings(mDevice, startId);
} else {
createDialog(mContext, device, state, startId);
}
}
private synchronized void handleUndocked(Context context, LocalBluetoothManager localManager,
BluetoothDevice device) {
mRunnable = null;
LocalBluetoothProfileManager.removeServiceListener(this);
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
@@ -778,4 +806,15 @@ public class DockService extends Service implements AlertDialog.OnMultiChoiceCli
editor.commit();
return;
}
public synchronized void onServiceConnected() {
if (mRunnable != null) {
mRunnable.run();
mRunnable = null;
LocalBluetoothProfileManager.removeServiceListener(this);
}
}
public void onServiceDisconnected() {
}
}

View File

@@ -28,6 +28,8 @@ import android.util.Log;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -53,6 +55,29 @@ public abstract class LocalBluetoothProfileManager {
BluetoothUuid.ObexObjectPush
};
/**
* An interface for notifying BluetoothHeadset IPC clients when they have
* been connected to the BluetoothHeadset service.
*/
public interface ServiceListener {
/**
* Called to notify the client when this proxy object has been
* connected to the BluetoothHeadset service. Clients must wait for
* this callback before making IPC calls on the BluetoothHeadset
* service.
*/
public void onServiceConnected();
/**
* Called to notify the client that this proxy object has been
* disconnected from the BluetoothHeadset service. Clients must not
* make IPC calls on the BluetoothHeadset service after this callback.
* This callback will currently only occur if the application hosting
* the BluetoothHeadset service, but may be called more often in future.
*/
public void onServiceDisconnected();
}
// TODO: close profiles when we're shutting down
private static Map<Profile, LocalBluetoothProfileManager> sProfileMap =
new HashMap<Profile, LocalBluetoothProfileManager>();
@@ -76,6 +101,26 @@ public abstract class LocalBluetoothProfileManager {
}
}
private static LinkedList<ServiceListener> mServiceListeners = new LinkedList<ServiceListener>();
public static void addServiceListener(ServiceListener l) {
mServiceListeners.add(l);
}
public static void removeServiceListener(ServiceListener l) {
mServiceListeners.remove(l);
}
public static boolean isManagerReady() {
// Getting just the headset profile is fine for now. Will need to deal with A2DP
// and others if they aren't always in a ready state.
LocalBluetoothProfileManager profileManager = sProfileMap.get(Profile.HEADSET);
if (profileManager == null) {
return sProfileMap.size() > 0;
}
return profileManager.isProfileReady();
}
public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager,
Profile profile) {
// Note: This code assumes that "localManager" is same as the
@@ -144,6 +189,8 @@ public abstract class LocalBluetoothProfileManager {
return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device));
}
public abstract boolean isProfileReady();
// TODO: int instead of enum
public enum Profile {
HEADSET(R.string.bluetooth_profile_headset),
@@ -247,6 +294,11 @@ public abstract class LocalBluetoothProfileManager {
return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
}
}
@Override
public boolean isProfileReady() {
return true;
}
}
/**
@@ -256,6 +308,7 @@ public abstract class LocalBluetoothProfileManager {
implements BluetoothHeadset.ServiceListener {
private BluetoothHeadset mService;
private Handler mUiHandler = new Handler();
private boolean profileReady = false;
public HeadsetProfileManager(LocalBluetoothManager localManager) {
super(localManager);
@@ -263,6 +316,7 @@ public abstract class LocalBluetoothProfileManager {
}
public void onServiceConnected() {
profileReady = true;
// This could be called on a non-UI thread, funnel to UI thread.
mUiHandler.post(new Runnable() {
public void run() {
@@ -277,9 +331,28 @@ public abstract class LocalBluetoothProfileManager {
BluetoothHeadset.STATE_CONNECTED);
}
});
if (mServiceListeners.size() > 0) {
Iterator<ServiceListener> it = mServiceListeners.iterator();
while(it.hasNext()) {
it.next().onServiceConnected();
}
}
}
public void onServiceDisconnected() {
profileReady = false;
if (mServiceListeners.size() > 0) {
Iterator<ServiceListener> it = mServiceListeners.iterator();
while(it.hasNext()) {
it.next().onServiceDisconnected();
}
}
}
@Override
public boolean isProfileReady() {
return profileReady;
}
@Override
@@ -423,6 +496,11 @@ public abstract class LocalBluetoothProfileManager {
public void setPreferred(BluetoothDevice device, boolean preferred) {
}
@Override
public boolean isProfileReady() {
return true;
}
@Override
public int convertState(int oppState) {
switch (oppState) {