Loading Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \ core/java/android/bluetooth/IBluetoothCallback.aidl \ core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \ core/java/android/bluetooth/IBluetoothHealth.aidl \ Loading core/java/android/bluetooth/BluetoothHeadset.java +52 −37 Original line number Diff line number Diff line Loading @@ -20,11 +20,11 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; Loading Loading @@ -283,6 +283,8 @@ public final class BluetoothHeadset implements BluetoothProfile { public static final int STATE_AUDIO_CONNECTED = 12; private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100; private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101; private Context mContext; private ServiceListener mServiceListener; Loading @@ -295,14 +297,7 @@ public final class BluetoothHeadset implements BluetoothProfile { if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); if (!up) { if (VDBG) Log.d(TAG,"Unbinding service..."); synchronized (mConnection) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } doUnbind(); } else { synchronized (mConnection) { try { Loading Loading @@ -339,15 +334,26 @@ public final class BluetoothHeadset implements BluetoothProfile { } boolean doBind() { Intent intent = new Intent(IBluetoothHeadset.class.getName()); ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, UserHandle.CURRENT_OR_SELF)) { Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent); try { return mAdapter.getBluetoothManager().bindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG, "Unable to bind HeadsetService", e); } return false; } return true; void doUnbind() { synchronized (mConnection) { if (mService != null) { try { mAdapter.getBluetoothManager().unbindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG,"Unable to unbind HeadsetService", e); } } } } /** Loading @@ -367,18 +373,8 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG,"",e); } } synchronized (mConnection) { if (mService != null) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } } mServiceListener = null; doUnbind(); } /** Loading Loading @@ -1063,17 +1059,15 @@ public final class BluetoothHeadset implements BluetoothProfile { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothHeadset.Stub.asInterface(service); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } @Override public void onServiceDisconnected(ComponentName className) { if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_DISCONNECTED)); } }; Loading @@ -1097,4 +1091,25 @@ public final class BluetoothHeadset implements BluetoothProfile { private static void log(String msg) { Log.d(TAG, msg); } private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_HEADSET_SERVICE_CONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } break; } case MESSAGE_HEADSET_SERVICE_DISCONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } break; } } } }; } core/java/android/bluetooth/IBluetoothManager.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.bluetooth; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; /** Loading @@ -39,6 +40,9 @@ interface IBluetoothManager int getState(); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); String getAddress(); String getName(); Loading core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl 0 → 100755 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; import android.content.ComponentName; import android.os.IBinder; /** * Callback for bluetooth profile connections. * * {@hide} */ interface IBluetoothProfileServiceConnection { void onServiceConnected(in ComponentName comp, in IBinder service); void onServiceDisconnected(in ComponentName comp); } services/core/java/com/android/server/BluetoothManagerService.java +240 −1 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothHeadset; import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -80,6 +82,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int ERROR_RESTART_TIME_MS = 3000; //Maximum msec to delay MESSAGE_USER_SWITCHED private static final int USER_SWITCHED_TIME_MS = 200; // Delay for the addProxy function in msec private static final int ADD_PROXY_DELAY_MS = 100; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; Loading @@ -96,6 +100,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200; private static final int MESSAGE_USER_SWITCHED = 300; private static final int MESSAGE_USER_UNLOCKED = 301; private static final int MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; private static final int MAX_SAVE_RETRIES = 3; private static final int MAX_ERROR_RESTART_RETRIES = 6; Loading Loading @@ -146,6 +152,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mIntentPending = false; private int mIBluetoothConnectedMsgQueued = 0; // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -738,6 +749,69 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return mBluetoothGatt; } @Override public boolean bindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { if (!mEnable) { if (DBG) { Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile + ", while Bluetooth was disabled"); } return false; } synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { if (DBG) { Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + bluetoothProfile); } if (bluetoothProfile != BluetoothProfile.HEADSET) return false; Intent intent = new Intent(IBluetoothHeadset.class.getName()); psc = new ProfileServiceConnections(intent); if (!psc.bindService()) return false; mProfileServices.put(new Integer(bluetoothProfile), psc); } } // Introducing a delay to give the client app time to prepare Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); addProxyMsg.arg1 = bluetoothProfile; addProxyMsg.obj = proxy; mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); return true; } @Override public void unbindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { return; } psc.removeProxy(proxy); } } private void unbindAllBluetoothProfileServices() { synchronized (mProfileServices) { for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); try { mContext.unbindService(psc); } catch (IllegalArgumentException e) { Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); } psc.removeAllProxies(); } mProfileServices.clear(); } } /** * Send enable message and set adapter name and address. Called when the boot phase becomes * PHASE_SYSTEM_SERVICES_READY. Loading Loading @@ -770,6 +844,148 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget(); } /** * This class manages the clients connected to a given ProfileService * and maintains the connection with that service. */ final private class ProfileServiceConnections implements ServiceConnection, IBinder.DeathRecipient { final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = new RemoteCallbackList <IBluetoothProfileServiceConnection>(); IBinder mService; ComponentName mClassName; Intent mIntent; boolean mInvokingProxyCallbacks = false; ProfileServiceConnections(Intent intent) { mService = null; mClassName = null; mIntent = intent; } private boolean bindService() { if (mIntent != null && mService == null && doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); return true; } Slog.w(TAG, "Unable to bind with intent: " + mIntent); return false; } private void addProxy(IBluetoothProfileServiceConnection proxy) { mProxies.register(proxy); if (mService != null) { try{ proxy.onServiceConnected(mClassName, mService); } catch (RemoteException e) { Slog.e(TAG, "Unable to connect to proxy", e); } } else { if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessage(msg); } } } private void removeProxy(IBluetoothProfileServiceConnection proxy) { if (proxy != null) { if (mProxies.unregister(proxy)) { try { proxy.onServiceDisconnected(mClassName); } catch (RemoteException e) { Slog.e(TAG, "Unable to disconnect proxy", e); } } } else { Slog.w(TAG, "Trying to remove a null proxy"); } } private void removeAllProxies() { onServiceDisconnected(mClassName); mProxies.kill(); } @Override public void onServiceConnected(ComponentName className, IBinder service) { // remove timeout message mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); mService = service; mClassName = className; try { mService.linkToDeath(this, 0); } catch (RemoteException e) { Slog.e(TAG, "Unable to linkToDeath", e); } if (mInvokingProxyCallbacks) { Slog.e(TAG, "Proxy callbacks already in progress."); return; } mInvokingProxyCallbacks = true; final int n = mProxies.beginBroadcast(); try { for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceConnected(className, service); } catch (RemoteException e) { Slog.e(TAG, "Unable to connect to proxy", e); } } } finally { mProxies.finishBroadcast(); mInvokingProxyCallbacks = false; } } @Override public void onServiceDisconnected(ComponentName className) { if (mService == null) return; mService.unlinkToDeath(this, 0); mService = null; mClassName = null; if (mInvokingProxyCallbacks) { Slog.e(TAG, "Proxy callbacks already in progress."); return; } mInvokingProxyCallbacks = true; final int n = mProxies.beginBroadcast(); try { for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceDisconnected(className); } catch (RemoteException e) { Slog.e(TAG, "Unable to disconnect from proxy", e); } } } finally { mProxies.finishBroadcast(); mInvokingProxyCallbacks = false; } } @Override public void binderDied() { if (DBG) { Slog.w(TAG, "Profile service for profile: " + mClassName + " died."); } onServiceDisconnected(mClassName); // Trigger rebind Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void sendBluetoothStateCallback(boolean isUp) { try { int n = mStateChangeCallbacks.beginBroadcast(); Loading Loading @@ -1058,6 +1274,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } case MESSAGE_ADD_PROXY_DELAYED: { ProfileServiceConnections psc = mProfileServices.get( new Integer(msg.arg1)); if (psc == null) { break; } IBluetoothProfileServiceConnection proxy = (IBluetoothProfileServiceConnection) msg.obj; psc.addProxy(proxy); break; } case MESSAGE_BIND_PROFILE_SERVICE: { ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { break; } psc.bindService(); break; } case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); Loading Loading @@ -1289,6 +1527,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); } unbindAllBluetoothProfileServices(); // disable handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close Loading Loading
Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \ core/java/android/bluetooth/IBluetoothCallback.aidl \ core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \ core/java/android/bluetooth/IBluetoothHealth.aidl \ Loading
core/java/android/bluetooth/BluetoothHeadset.java +52 −37 Original line number Diff line number Diff line Loading @@ -20,11 +20,11 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; Loading Loading @@ -283,6 +283,8 @@ public final class BluetoothHeadset implements BluetoothProfile { public static final int STATE_AUDIO_CONNECTED = 12; private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100; private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101; private Context mContext; private ServiceListener mServiceListener; Loading @@ -295,14 +297,7 @@ public final class BluetoothHeadset implements BluetoothProfile { if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); if (!up) { if (VDBG) Log.d(TAG,"Unbinding service..."); synchronized (mConnection) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } doUnbind(); } else { synchronized (mConnection) { try { Loading Loading @@ -339,15 +334,26 @@ public final class BluetoothHeadset implements BluetoothProfile { } boolean doBind() { Intent intent = new Intent(IBluetoothHeadset.class.getName()); ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, UserHandle.CURRENT_OR_SELF)) { Log.e(TAG, "Could not bind to Bluetooth Headset Service with " + intent); try { return mAdapter.getBluetoothManager().bindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG, "Unable to bind HeadsetService", e); } return false; } return true; void doUnbind() { synchronized (mConnection) { if (mService != null) { try { mAdapter.getBluetoothManager().unbindBluetoothProfileService( BluetoothProfile.HEADSET, mConnection); } catch (RemoteException e) { Log.e(TAG,"Unable to unbind HeadsetService", e); } } } } /** Loading @@ -367,18 +373,8 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.e(TAG,"",e); } } synchronized (mConnection) { if (mService != null) { try { mService = null; mContext.unbindService(mConnection); } catch (Exception re) { Log.e(TAG,"",re); } } } mServiceListener = null; doUnbind(); } /** Loading Loading @@ -1063,17 +1059,15 @@ public final class BluetoothHeadset implements BluetoothProfile { public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); mService = IBluetoothHeadset.Stub.asInterface(service); if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } @Override public void onServiceDisconnected(ComponentName className) { if (DBG) Log.d(TAG, "Proxy object disconnected"); mService = null; if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_DISCONNECTED)); } }; Loading @@ -1097,4 +1091,25 @@ public final class BluetoothHeadset implements BluetoothProfile { private static void log(String msg) { Log.d(TAG, msg); } private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_HEADSET_SERVICE_CONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, BluetoothHeadset.this); } break; } case MESSAGE_HEADSET_SERVICE_DISCONNECTED: { if (mServiceListener != null) { mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET); } break; } } } }; }
core/java/android/bluetooth/IBluetoothManager.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.bluetooth; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; /** Loading @@ -39,6 +40,9 @@ interface IBluetoothManager int getState(); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); void unbindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); String getAddress(); String getName(); Loading
core/java/android/bluetooth/IBluetoothProfileServiceConnection.aidl 0 → 100755 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; import android.content.ComponentName; import android.os.IBinder; /** * Callback for bluetooth profile connections. * * {@hide} */ interface IBluetoothProfileServiceConnection { void onServiceConnected(in ComponentName comp, in IBinder service); void onServiceDisconnected(in ComponentName comp); }
services/core/java/com/android/server/BluetoothManagerService.java +240 −1 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothGatt; import android.bluetooth.IBluetoothHeadset; import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -80,6 +82,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int ERROR_RESTART_TIME_MS = 3000; //Maximum msec to delay MESSAGE_USER_SWITCHED private static final int USER_SWITCHED_TIME_MS = 200; // Delay for the addProxy function in msec private static final int ADD_PROXY_DELAY_MS = 100; private static final int MESSAGE_ENABLE = 1; private static final int MESSAGE_DISABLE = 2; Loading @@ -96,6 +100,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200; private static final int MESSAGE_USER_SWITCHED = 300; private static final int MESSAGE_USER_UNLOCKED = 301; private static final int MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; private static final int MAX_SAVE_RETRIES = 3; private static final int MAX_ERROR_RESTART_RETRIES = 6; Loading Loading @@ -146,6 +152,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private boolean mIntentPending = false; private int mIBluetoothConnectedMsgQueued = 0; // Save a ProfileServiceConnections object for each of the bound // bluetooth profile services private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -738,6 +749,69 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return mBluetoothGatt; } @Override public boolean bindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { if (!mEnable) { if (DBG) { Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile + ", while Bluetooth was disabled"); } return false; } synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { if (DBG) { Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: " + bluetoothProfile); } if (bluetoothProfile != BluetoothProfile.HEADSET) return false; Intent intent = new Intent(IBluetoothHeadset.class.getName()); psc = new ProfileServiceConnections(intent); if (!psc.bindService()) return false; mProfileServices.put(new Integer(bluetoothProfile), psc); } } // Introducing a delay to give the client app time to prepare Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED); addProxyMsg.arg1 = bluetoothProfile; addProxyMsg.obj = proxy; mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS); return true; } @Override public void unbindBluetoothProfileService(int bluetoothProfile, IBluetoothProfileServiceConnection proxy) { synchronized (mProfileServices) { ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); if (psc == null) { return; } psc.removeProxy(proxy); } } private void unbindAllBluetoothProfileServices() { synchronized (mProfileServices) { for (Integer i : mProfileServices.keySet()) { ProfileServiceConnections psc = mProfileServices.get(i); try { mContext.unbindService(psc); } catch (IllegalArgumentException e) { Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e); } psc.removeAllProxies(); } mProfileServices.clear(); } } /** * Send enable message and set adapter name and address. Called when the boot phase becomes * PHASE_SYSTEM_SERVICES_READY. Loading Loading @@ -770,6 +844,148 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget(); } /** * This class manages the clients connected to a given ProfileService * and maintains the connection with that service. */ final private class ProfileServiceConnections implements ServiceConnection, IBinder.DeathRecipient { final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies = new RemoteCallbackList <IBluetoothProfileServiceConnection>(); IBinder mService; ComponentName mClassName; Intent mIntent; boolean mInvokingProxyCallbacks = false; ProfileServiceConnections(Intent intent) { mService = null; mClassName = null; mIntent = intent; } private boolean bindService() { if (mIntent != null && mService == null && doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); return true; } Slog.w(TAG, "Unable to bind with intent: " + mIntent); return false; } private void addProxy(IBluetoothProfileServiceConnection proxy) { mProxies.register(proxy); if (mService != null) { try{ proxy.onServiceConnected(mClassName, mService); } catch (RemoteException e) { Slog.e(TAG, "Unable to connect to proxy", e); } } else { if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) { Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessage(msg); } } } private void removeProxy(IBluetoothProfileServiceConnection proxy) { if (proxy != null) { if (mProxies.unregister(proxy)) { try { proxy.onServiceDisconnected(mClassName); } catch (RemoteException e) { Slog.e(TAG, "Unable to disconnect proxy", e); } } } else { Slog.w(TAG, "Trying to remove a null proxy"); } } private void removeAllProxies() { onServiceDisconnected(mClassName); mProxies.kill(); } @Override public void onServiceConnected(ComponentName className, IBinder service) { // remove timeout message mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this); mService = service; mClassName = className; try { mService.linkToDeath(this, 0); } catch (RemoteException e) { Slog.e(TAG, "Unable to linkToDeath", e); } if (mInvokingProxyCallbacks) { Slog.e(TAG, "Proxy callbacks already in progress."); return; } mInvokingProxyCallbacks = true; final int n = mProxies.beginBroadcast(); try { for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceConnected(className, service); } catch (RemoteException e) { Slog.e(TAG, "Unable to connect to proxy", e); } } } finally { mProxies.finishBroadcast(); mInvokingProxyCallbacks = false; } } @Override public void onServiceDisconnected(ComponentName className) { if (mService == null) return; mService.unlinkToDeath(this, 0); mService = null; mClassName = null; if (mInvokingProxyCallbacks) { Slog.e(TAG, "Proxy callbacks already in progress."); return; } mInvokingProxyCallbacks = true; final int n = mProxies.beginBroadcast(); try { for (int i = 0; i < n; i++) { try { mProxies.getBroadcastItem(i).onServiceDisconnected(className); } catch (RemoteException e) { Slog.e(TAG, "Unable to disconnect from proxy", e); } } } finally { mProxies.finishBroadcast(); mInvokingProxyCallbacks = false; } } @Override public void binderDied() { if (DBG) { Slog.w(TAG, "Profile service for profile: " + mClassName + " died."); } onServiceDisconnected(mClassName); // Trigger rebind Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE); msg.obj = this; mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS); } } private void sendBluetoothStateCallback(boolean isUp) { try { int n = mStateChangeCallbacks.beginBroadcast(); Loading Loading @@ -1058,6 +1274,28 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; } case MESSAGE_ADD_PROXY_DELAYED: { ProfileServiceConnections psc = mProfileServices.get( new Integer(msg.arg1)); if (psc == null) { break; } IBluetoothProfileServiceConnection proxy = (IBluetoothProfileServiceConnection) msg.obj; psc.addProxy(proxy); break; } case MESSAGE_BIND_PROFILE_SERVICE: { ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj; removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj); if (psc == null) { break; } psc.bindService(); break; } case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: { if (DBG) Slog.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1); Loading Loading @@ -1289,6 +1527,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); } unbindAllBluetoothProfileServices(); // disable handleDisable(); // Pbap service need receive STATE_TURNING_OFF intent to close Loading