diff options
-rw-r--r-- | src/com/android/settings/bluetooth/DockService.java | 55 | ||||
-rw-r--r-- | src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java | 78 |
2 files changed, 125 insertions, 8 deletions
diff --git a/src/com/android/settings/bluetooth/DockService.java b/src/com/android/settings/bluetooth/DockService.java index f318987..d0f8099 100644 --- a/src/com/android/settings/bluetooth/DockService.java +++ b/src/com/android/settings/bluetooth/DockService.java @@ -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() { + } } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java index f3aaade..6179dc7 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java @@ -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 @@ -424,6 +497,11 @@ public abstract class LocalBluetoothProfileManager { } @Override + public boolean isProfileReady() { + return true; + } + + @Override public int convertState(int oppState) { switch (oppState) { case 0: |