Merge "Fix binder leakage when turning off Bluetooth"

This commit is contained in:
Treehugger Robot
2019-05-06 03:21:18 +00:00
committed by Gerrit Code Review
16 changed files with 682 additions and 1610 deletions

View File

@@ -22,23 +22,16 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/** /**
@@ -209,43 +202,13 @@ public final class BluetoothA2dp implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
private Context mContext;
private ServiceListener mServiceListener;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
@GuardedBy("mServiceLock")
private IBluetoothA2dp mService;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
new IBluetoothStateChangeCallback.Stub() { IBluetoothA2dp.class.getName()) {
public void onBluetoothStateChange(boolean up) { @Override
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); public IBluetoothA2dp getServiceInterface(IBinder service) {
if (!up) { return IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
if (VDBG) Log.d(TAG, "Unbinding service...");
try {
mServiceLock.writeLock().lock();
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.writeLock().unlock();
}
} else {
try {
mServiceLock.readLock().lock();
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.readLock().unlock();
}
}
} }
}; };
@@ -253,57 +216,18 @@ public final class BluetoothA2dp implements BluetoothProfile {
* Create a BluetoothA2dp proxy object for interacting with the local * Create a BluetoothA2dp proxy object for interacting with the local
* Bluetooth A2DP service. * Bluetooth A2DP service.
*/ */
/*package*/ BluetoothA2dp(Context context, ServiceListener l) { /*package*/ BluetoothA2dp(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothA2dp.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 A2DP Service with " + intent);
return false;
}
return true;
} }
@UnsupportedAppUsage @UnsupportedAppUsage
/*package*/ void close() { /*package*/ void close() {
mServiceListener = null; mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
try { private IBluetoothA2dp getService() {
mServiceLock.writeLock().lock(); return mProfileConnector.getService();
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.writeLock().unlock();
}
} }
@Override @Override
@@ -333,17 +257,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
return mService.connect(device); return service.connect(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -376,17 +298,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
return mService.disconnect(device); return service.disconnect(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -397,17 +317,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
return mService.getConnectedDevices(); return service.getConnectedDevices();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -418,17 +336,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
return mService.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -439,18 +355,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getConnectionState(device); return service.getConnectionState(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.STATE_DISCONNECTED; return BluetoothProfile.STATE_DISCONNECTED;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED; return BluetoothProfile.STATE_DISCONNECTED;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -480,18 +394,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
public boolean setActiveDevice(@Nullable BluetoothDevice device) { public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")"); if (DBG) log("setActiveDevice(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& ((device == null) || isValidDevice(device))) { && ((device == null) || isValidDevice(device))) {
return mService.setActiveDevice(device); return service.setActiveDevice(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -511,17 +423,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public BluetoothDevice getActiveDevice() { public BluetoothDevice getActiveDevice() {
if (VDBG) log("getActiveDevice()"); if (VDBG) log("getActiveDevice()");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
return mService.getActiveDevice(); return service.getActiveDevice();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return null; return null;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return null; return null;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -543,22 +453,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
return false; return false;
} }
return mService.setPriority(device, priority); return service.setPriority(device, priority);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -578,18 +486,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getPriority(device); return service.getPriority(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -602,17 +508,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
public boolean isAvrcpAbsoluteVolumeSupported() { public boolean isAvrcpAbsoluteVolumeSupported() {
if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported"); if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
return mService.isAvrcpAbsoluteVolumeSupported(); return service.isAvrcpAbsoluteVolumeSupported();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e); Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -625,15 +529,13 @@ public final class BluetoothA2dp implements BluetoothProfile {
public void setAvrcpAbsoluteVolume(int volume) { public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume"); if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
mService.setAvrcpAbsoluteVolume(volume); service.setAvrcpAbsoluteVolume(volume);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e); Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -646,18 +548,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/ */
public boolean isA2dpPlaying(BluetoothDevice device) { public boolean isA2dpPlaying(BluetoothDevice device) {
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.isA2dpPlaying(device); return service.isA2dpPlaying(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -694,19 +594,17 @@ public final class BluetoothA2dp implements BluetoothProfile {
public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) { public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")"); if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
return mService.getCodecStatus(device); return service.getCodecStatus(device);
} }
if (mService == null) { if (service == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
} }
return null; return null;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in getCodecStatus()", e); Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
return null; return null;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -723,17 +621,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
BluetoothCodecConfig codecConfig) { BluetoothCodecConfig codecConfig) {
if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")"); if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
mService.setCodecConfigPreference(device, codecConfig); service.setCodecConfigPreference(device, codecConfig);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return; return;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e); Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
return; return;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -772,21 +668,19 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/ */
private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) { private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled()) { if (service != null && isEnabled()) {
if (enable) { if (enable) {
mService.enableOptionalCodecs(device); service.enableOptionalCodecs(device);
} else { } else {
mService.disableOptionalCodecs(device); service.disableOptionalCodecs(device);
} }
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return; return;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e); Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
return; return;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -801,17 +695,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public int supportsOptionalCodecs(BluetoothDevice device) { public int supportsOptionalCodecs(BluetoothDevice device) {
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
return mService.supportsOptionalCodecs(device); return service.supportsOptionalCodecs(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return OPTIONAL_CODECS_SUPPORT_UNKNOWN; return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
return OPTIONAL_CODECS_SUPPORT_UNKNOWN; return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -826,17 +718,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public int getOptionalCodecsEnabled(BluetoothDevice device) { public int getOptionalCodecsEnabled(BluetoothDevice device) {
try { try {
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
return mService.getOptionalCodecsEnabled(device); return service.getOptionalCodecsEnabled(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return OPTIONAL_CODECS_PREF_UNKNOWN; return OPTIONAL_CODECS_PREF_UNKNOWN;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
return OPTIONAL_CODECS_PREF_UNKNOWN; return OPTIONAL_CODECS_PREF_UNKNOWN;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -858,18 +748,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value); Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
return; return;
} }
mServiceLock.readLock().lock(); final IBluetoothA2dp service = getService();
if (mService != null && isEnabled() if (service != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
mService.setOptionalCodecsEnabled(device, value); service.setOptionalCodecsEnabled(device, value);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return; return;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return; return;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -900,35 +788,6 @@ public final class BluetoothA2dp implements BluetoothProfile {
} }
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
try {
mServiceLock.writeLock().lock();
mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
} finally {
mServiceLock.writeLock().unlock();
}
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
try {
mServiceLock.writeLock().lock();
mService = null;
} finally {
mServiceLock.writeLock().unlock();
}
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
return false; return false;

View File

@@ -17,10 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -124,37 +121,13 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
public static final String EXTRA_AUDIO_CONFIG = public static final String EXTRA_AUDIO_CONFIG =
"android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG"; "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
private Context mContext;
private ServiceListener mServiceListener;
private volatile IBluetoothA2dpSink mService;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
new IBluetoothStateChangeCallback.Stub() { "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) {
public void onBluetoothStateChange(boolean up) { @Override
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); public IBluetoothA2dpSink getServiceInterface(IBinder service) {
if (!up) { return IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
if (VDBG) Log.d(TAG, "Unbinding service...");
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
@@ -162,55 +135,17 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* Create a BluetoothA2dp proxy object for interacting with the local * Create a BluetoothA2dp proxy object for interacting with the local
* Bluetooth A2DP service. * Bluetooth A2DP service.
*/ */
/*package*/ BluetoothA2dpSink(Context context, ServiceListener l) { /*package*/ BluetoothA2dpSink(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothA2dpSink.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
return false;
}
return true;
} }
/*package*/ void close() { /*package*/ void close() {
mServiceListener = null; mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothA2dpSink getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
@Override @Override
@@ -241,7 +176,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
*/ */
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.connect(device); return service.connect(device);
@@ -282,7 +217,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -301,7 +236,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -320,7 +255,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -339,7 +274,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -365,7 +300,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
*/ */
public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
if (VDBG) log("getAudioConfig(" + device + ")"); if (VDBG) log("getAudioConfig(" + device + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getAudioConfig(device); return service.getAudioConfig(device);
@@ -395,7 +330,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -427,7 +362,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -448,7 +383,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @param device BluetoothDevice device * @param device BluetoothDevice device
*/ */
public boolean isA2dpPlaying(BluetoothDevice device) { public boolean isA2dpPlaying(BluetoothDevice device) {
final IBluetoothA2dpSink service = mService; final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.isA2dpPlaying(device); return service.isA2dpPlaying(device);
@@ -487,25 +422,6 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
} }
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
BluetoothA2dpSink.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON; return mAdapter.getState() == BluetoothAdapter.STATE_ON;
} }

View File

@@ -16,10 +16,7 @@
package android.bluetooth; package android.bluetooth;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -79,37 +76,14 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
public static final String EXTRA_PLAYER_SETTING = public static final String EXTRA_PLAYER_SETTING =
"android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING"; "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
private Context mContext;
private ServiceListener mServiceListener;
private volatile IBluetoothAvrcpController mService;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothAvrcpController> mProfileConnector =
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER,
new IBluetoothStateChangeCallback.Stub() { "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) {
public void onBluetoothStateChange(boolean up) { @Override
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); public IBluetoothAvrcpController getServiceInterface(IBinder service) {
if (!up) { return IBluetoothAvrcpController.Stub.asInterface(
if (VDBG) Log.d(TAG, "Unbinding service..."); Binder.allowBlocking(service));
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
@@ -117,55 +91,17 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
* Create a BluetoothAvrcpController proxy object for interacting with the local * Create a BluetoothAvrcpController proxy object for interacting with the local
* Bluetooth AVRCP service. * Bluetooth AVRCP service.
*/ */
/*package*/ BluetoothAvrcpController(Context context, ServiceListener l) { /*package*/ BluetoothAvrcpController(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
return false;
}
return true;
} }
/*package*/ void close() { /*package*/ void close() {
mServiceListener = null; mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothAvrcpController getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
@Override @Override
@@ -179,7 +115,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -198,7 +135,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -217,7 +155,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -238,7 +177,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getPlayerSettings"); if (DBG) Log.d(TAG, "getPlayerSettings");
BluetoothAvrcpPlayerSettings settings = null; BluetoothAvrcpPlayerSettings settings = null;
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
settings = service.getPlayerSettings(device); settings = service.getPlayerSettings(device);
@@ -256,7 +196,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
*/ */
public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.setPlayerApplicationSetting(plAppSetting); return service.setPlayerApplicationSetting(plAppSetting);
@@ -276,7 +217,8 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = "
+ keyState); + keyState);
final IBluetoothAvrcpController service = mService; final IBluetoothAvrcpController service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
service.sendGroupNavigationCmd(device, keyCode, keyState); service.sendGroupNavigationCmd(device, keyCode, keyState);
@@ -289,25 +231,6 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
if (service == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothAvrcpController.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
BluetoothAvrcpController.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON; return mAdapter.getState() == BluetoothAdapter.STATE_ON;
} }

View File

@@ -337,20 +337,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
public void onBluetoothStateChange(boolean up) { public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) { if (!up) {
if (VDBG) Log.d(TAG, "Unbinding service...");
doUnbind(); doUnbind();
} else { } else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind(); doBind();
} }
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
@@ -374,24 +364,32 @@ public final class BluetoothHeadset implements BluetoothProfile {
doBind(); doBind();
} }
boolean doBind() { private boolean doBind() {
synchronized (mConnection) {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
try { try {
return mAdapter.getBluetoothManager().bindBluetoothProfileService( return mAdapter.getBluetoothManager().bindBluetoothProfileService(
BluetoothProfile.HEADSET, mConnection); BluetoothProfile.HEADSET, mConnection);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Unable to bind HeadsetService", e); Log.e(TAG, "Unable to bind HeadsetService", e);
} }
}
}
return false; return false;
} }
void doUnbind() { private void doUnbind() {
synchronized (mConnection) { synchronized (mConnection) {
if (mService != null) { if (mService != null) {
if (VDBG) Log.d(TAG, "Unbinding service...");
try { try {
mAdapter.getBluetoothManager().unbindBluetoothProfileService( mAdapter.getBluetoothManager().unbindBluetoothProfileService(
BluetoothProfile.HEADSET, mConnection); BluetoothProfile.HEADSET, mConnection);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Unable to unbind HeadsetService", e); Log.e(TAG, "Unable to unbind HeadsetService", e);
} finally {
mService = null;
} }
} }
} }
@@ -411,8 +409,8 @@ public final class BluetoothHeadset implements BluetoothProfile {
if (mgr != null) { if (mgr != null) {
try { try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) { } catch (RemoteException re) {
Log.e(TAG, "", e); Log.e(TAG, "", re);
} }
} }
mServiceListener = null; mServiceListener = null;
@@ -1169,7 +1167,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
@Override @Override
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected"); if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null; doUnbind();
mHandler.sendMessage(mHandler.obtainMessage( mHandler.sendMessage(mHandler.obtainMessage(
MESSAGE_HEADSET_SERVICE_DISCONNECTED)); MESSAGE_HEADSET_SERVICE_DISCONNECTED));
} }

View File

@@ -17,10 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
@@ -366,73 +363,22 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
public static final int CALL_ACCEPT_HOLD = 1; public static final int CALL_ACCEPT_HOLD = 1;
public static final int CALL_ACCEPT_TERMINATE = 2; public static final int CALL_ACCEPT_TERMINATE = 2;
private Context mContext;
private ServiceListener mServiceListener;
private volatile IBluetoothHeadsetClient mService;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothHeadsetClient> mProfileConnector =
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new BluetoothProfileConnector(this, BluetoothProfile.HEADSET_CLIENT,
new IBluetoothStateChangeCallback.Stub() { "BluetoothHeadsetClient", IBluetoothHeadsetClient.class.getName()) {
@Override @Override
public void onBluetoothStateChange(boolean up) { public IBluetoothHeadsetClient getServiceInterface(IBinder service) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); return IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));
if (!up) {
if (VDBG) Log.d(TAG, "Unbinding service...");
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
Intent intent = new Intent(
IBluetoothHeadsetClient.class.getName());
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
/** /**
* Create a BluetoothHeadsetClient proxy object. * Create a BluetoothHeadsetClient proxy object.
*/ */
/*package*/ BluetoothHeadsetClient(Context context, ServiceListener l) { /*package*/ BluetoothHeadsetClient(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
mProfileConnector.connect(context, listener);
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
return false;
}
return true;
} }
/** /**
@@ -443,27 +389,11 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
/*package*/ void close() { /*package*/ void close() {
if (VDBG) log("close()"); if (VDBG) log("close()");
mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothHeadsetClient getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -480,7 +410,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.connect(device); return service.connect(device);
@@ -503,7 +434,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -524,7 +456,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -547,7 +480,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -569,7 +503,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")"); if (VDBG) log("getConnectionState(" + device + ")");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -589,7 +524,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -611,7 +547,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -637,7 +574,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean startVoiceRecognition(BluetoothDevice device) { public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()"); if (DBG) log("startVoiceRecognition()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.startVoiceRecognition(device); return service.startVoiceRecognition(device);
@@ -662,7 +600,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean stopVoiceRecognition(BluetoothDevice device) { public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()"); if (DBG) log("stopVoiceRecognition()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.stopVoiceRecognition(device); return service.stopVoiceRecognition(device);
@@ -682,7 +621,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()"); if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getCurrentCalls(device); return service.getCurrentCalls(device);
@@ -702,7 +642,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public Bundle getCurrentAgEvents(BluetoothDevice device) { public Bundle getCurrentAgEvents(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()"); if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getCurrentAgEvents(device); return service.getCurrentAgEvents(device);
@@ -726,7 +667,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean acceptCall(BluetoothDevice device, int flag) { public boolean acceptCall(BluetoothDevice device, int flag) {
if (DBG) log("acceptCall()"); if (DBG) log("acceptCall()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.acceptCall(device, flag); return service.acceptCall(device, flag);
@@ -747,7 +689,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean holdCall(BluetoothDevice device) { public boolean holdCall(BluetoothDevice device) {
if (DBG) log("holdCall()"); if (DBG) log("holdCall()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.holdCall(device); return service.holdCall(device);
@@ -773,7 +716,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean rejectCall(BluetoothDevice device) { public boolean rejectCall(BluetoothDevice device) {
if (DBG) log("rejectCall()"); if (DBG) log("rejectCall()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.rejectCall(device); return service.rejectCall(device);
@@ -803,7 +747,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
if (DBG) log("terminateCall()"); if (DBG) log("terminateCall()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.terminateCall(device, call); return service.terminateCall(device, call);
@@ -831,7 +776,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean enterPrivateMode(BluetoothDevice device, int index) { public boolean enterPrivateMode(BluetoothDevice device, int index) {
if (DBG) log("enterPrivateMode()"); if (DBG) log("enterPrivateMode()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.enterPrivateMode(device, index); return service.enterPrivateMode(device, index);
@@ -858,7 +804,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean explicitCallTransfer(BluetoothDevice device) { public boolean explicitCallTransfer(BluetoothDevice device) {
if (DBG) log("explicitCallTransfer()"); if (DBG) log("explicitCallTransfer()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.explicitCallTransfer(device); return service.explicitCallTransfer(device);
@@ -881,7 +828,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
if (DBG) log("dial()"); if (DBG) log("dial()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.dial(device, number); return service.dial(device, number);
@@ -905,7 +853,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean sendDTMF(BluetoothDevice device, byte code) { public boolean sendDTMF(BluetoothDevice device, byte code) {
if (DBG) log("sendDTMF()"); if (DBG) log("sendDTMF()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.sendDTMF(device, code); return service.sendDTMF(device, code);
@@ -931,7 +880,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean getLastVoiceTagNumber(BluetoothDevice device) { public boolean getLastVoiceTagNumber(BluetoothDevice device) {
if (DBG) log("getLastVoiceTagNumber()"); if (DBG) log("getLastVoiceTagNumber()");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getLastVoiceTagNumber(device); return service.getLastVoiceTagNumber(device);
@@ -951,7 +901,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public int getAudioState(BluetoothDevice device) { public int getAudioState(BluetoothDevice device) {
if (VDBG) log("getAudioState"); if (VDBG) log("getAudioState");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getAudioState(device); return service.getAudioState(device);
@@ -974,7 +925,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) {
if (VDBG) log("setAudioRouteAllowed"); if (VDBG) log("setAudioRouteAllowed");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
service.setAudioRouteAllowed(device, allowed); service.setAudioRouteAllowed(device, allowed);
@@ -996,7 +948,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
*/ */
public boolean getAudioRouteAllowed(BluetoothDevice device) { public boolean getAudioRouteAllowed(BluetoothDevice device) {
if (VDBG) log("getAudioRouteAllowed"); if (VDBG) log("getAudioRouteAllowed");
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getAudioRouteAllowed(device); return service.getAudioRouteAllowed(device);
@@ -1020,7 +973,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent; * otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/ */
public boolean connectAudio(BluetoothDevice device) { public boolean connectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.connectAudio(device); return service.connectAudio(device);
@@ -1044,7 +998,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent; * otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/ */
public boolean disconnectAudio(BluetoothDevice device) { public boolean disconnectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.disconnectAudio(device); return service.disconnectAudio(device);
@@ -1065,7 +1020,8 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return bundle of AG features; null if no service or AG not connected * @return bundle of AG features; null if no service or AG not connected
*/ */
public Bundle getCurrentAgFeatures(BluetoothDevice device) { public Bundle getCurrentAgFeatures(BluetoothDevice device) {
final IBluetoothHeadsetClient service = mService; final IBluetoothHeadsetClient service =
getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getCurrentAgFeatures(device); return service.getCurrentAgFeatures(device);
@@ -1079,29 +1035,6 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
return null; return null;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
BluetoothHeadsetClient.this);
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON; return mAdapter.getState() == BluetoothAdapter.STATE_ON;
} }

View File

@@ -22,20 +22,14 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/** /**
* This class provides the public APIs to control the Hearing Aid profile. * This class provides the public APIs to control the Hearing Aid profile.
@@ -128,41 +122,13 @@ public final class BluetoothHearingAid implements BluetoothProfile {
*/ */
public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID; public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
private Context mContext;
private ServiceListener mServiceListener;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
@GuardedBy("mServiceLock")
private IBluetoothHearingAid mService;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothHearingAid> mProfileConnector =
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = new BluetoothProfileConnector(this, BluetoothProfile.HEARING_AID,
new IBluetoothStateChangeCallback.Stub() { "BluetoothHearingAid", IBluetoothHearingAid.class.getName()) {
public void onBluetoothStateChange(boolean up) { @Override
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); public IBluetoothHearingAid getServiceInterface(IBinder service) {
if (!up) { return IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service));
if (VDBG) Log.d(TAG, "Unbinding service...");
try {
mServiceLock.writeLock().lock();
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.writeLock().unlock();
}
} else {
try {
mServiceLock.readLock().lock();
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.readLock().unlock();
}
}
} }
}; };
@@ -170,55 +136,17 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* Create a BluetoothHearingAid proxy object for interacting with the local * Create a BluetoothHearingAid proxy object for interacting with the local
* Bluetooth Hearing Aid service. * Bluetooth Hearing Aid service.
*/ */
/*package*/ BluetoothHearingAid(Context context, ServiceListener l) { /*package*/ BluetoothHearingAid(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
void doBind() {
Intent intent = new Intent(IBluetoothHearingAid.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
android.os.Process.myUserHandle())) {
Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent);
return;
}
} }
/*package*/ void close() { /*package*/ void close() {
mServiceListener = null; mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
try { private IBluetoothHearingAid getService() {
mServiceLock.writeLock().lock(); return mProfileConnector.getService();
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
} catch (Exception re) {
Log.e(TAG, "", re);
} finally {
mServiceLock.writeLock().unlock();
}
} }
/** /**
@@ -240,18 +168,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
*/ */
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled() && isValidDevice(device)) {
if (mService != null && isEnabled() && isValidDevice(device)) { return service.connect(device);
return mService.connect(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -282,18 +208,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
*/ */
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled() && isValidDevice(device)) {
if (mService != null && isEnabled() && isValidDevice(device)) { return service.disconnect(device);
return mService.disconnect(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -303,18 +227,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
@Override @Override
public @NonNull List<BluetoothDevice> getConnectedDevices() { public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()) {
if (mService != null && isEnabled()) { return service.getConnectedDevices();
return mService.getConnectedDevices();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -325,18 +247,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) { @NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()) {
if (mService != null && isEnabled()) { return service.getDevicesMatchingConnectionStates(states);
return mService.getDevicesMatchingConnectionStates(states);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>(); return new ArrayList<BluetoothDevice>();
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -347,19 +267,17 @@ public final class BluetoothHearingAid implements BluetoothProfile {
public @BluetoothProfile.BtProfileState int getConnectionState( public @BluetoothProfile.BtProfileState int getConnectionState(
@NonNull BluetoothDevice device) { @NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getConnectionState(device); return service.getConnectionState(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.STATE_DISCONNECTED; return BluetoothProfile.STATE_DISCONNECTED;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED; return BluetoothProfile.STATE_DISCONNECTED;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -387,20 +305,18 @@ public final class BluetoothHearingAid implements BluetoothProfile {
*/ */
public boolean setActiveDevice(@Nullable BluetoothDevice device) { public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")"); if (DBG) log("setActiveDevice(" + device + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& ((device == null) || isValidDevice(device))) { && ((device == null) || isValidDevice(device))) {
mService.setActiveDevice(device); service.setActiveDevice(device);
return true; return true;
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -418,18 +334,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
@RequiresPermission(Manifest.permission.BLUETOOTH) @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getActiveDevices() { public List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()"); if (VDBG) log("getActiveDevices()");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()) {
if (mService != null && isEnabled()) { return service.getActiveDevices();
return mService.getActiveDevices();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<>(); return new ArrayList<>();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<>(); return new ArrayList<>();
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -450,23 +364,21 @@ public final class BluetoothHearingAid implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
return false; return false;
} }
return mService.setPriority(device, priority); return service.setPriority(device, priority);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return false; return false;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false; return false;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -484,19 +396,17 @@ public final class BluetoothHearingAid implements BluetoothProfile {
@RequiresPermission(Manifest.permission.BLUETOOTH) @RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getPriority(device); return service.getPriority(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -535,18 +445,16 @@ public final class BluetoothHearingAid implements BluetoothProfile {
if (VDBG) { if (VDBG) {
log("getVolume()"); log("getVolume()");
} }
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()) {
if (mService != null && isEnabled()) { return service.getVolume();
return mService.getVolume();
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return 0; return 0;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return 0; return 0;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -566,21 +474,18 @@ public final class BluetoothHearingAid implements BluetoothProfile {
public void adjustVolume(int direction) { public void adjustVolume(int direction) {
if (DBG) log("adjustVolume(" + direction + ")"); if (DBG) log("adjustVolume(" + direction + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service == null) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
return; return;
} }
if (!isEnabled()) return; if (!isEnabled()) return;
mService.adjustVolume(direction); service.adjustVolume(direction);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -593,20 +498,18 @@ public final class BluetoothHearingAid implements BluetoothProfile {
public void setVolume(int volume) { public void setVolume(int volume) {
if (DBG) Log.d(TAG, "setVolume(" + volume + ")"); if (DBG) Log.d(TAG, "setVolume(" + volume + ")");
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service == null) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
return; return;
} }
if (!isEnabled()) return; if (!isEnabled()) return;
mService.setVolume(volume); service.setVolume(volume);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -622,21 +525,19 @@ public final class BluetoothHearingAid implements BluetoothProfile {
if (VDBG) { if (VDBG) {
log("getCustomerId(" + device + ")"); log("getCustomerId(" + device + ")");
} }
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service == null) {
if (mService == null) {
Log.w(TAG, "Proxy not attached to service"); Log.w(TAG, "Proxy not attached to service");
return HI_SYNC_ID_INVALID; return HI_SYNC_ID_INVALID;
} }
if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID; if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID;
return mService.getHiSyncId(device); return service.getHiSyncId(device);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return HI_SYNC_ID_INVALID; return HI_SYNC_ID_INVALID;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -652,19 +553,17 @@ public final class BluetoothHearingAid implements BluetoothProfile {
if (VDBG) { if (VDBG) {
log("getDeviceSide(" + device + ")"); log("getDeviceSide(" + device + ")");
} }
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getDeviceSide(device); return service.getDeviceSide(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return SIDE_LEFT; return SIDE_LEFT;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return SIDE_LEFT; return SIDE_LEFT;
} finally {
mServiceLock.readLock().unlock();
} }
} }
@@ -680,52 +579,20 @@ public final class BluetoothHearingAid implements BluetoothProfile {
if (VDBG) { if (VDBG) {
log("getDeviceMode(" + device + ")"); log("getDeviceMode(" + device + ")");
} }
final IBluetoothHearingAid service = getService();
try { try {
mServiceLock.readLock().lock(); if (service != null && isEnabled()
if (mService != null && isEnabled()
&& isValidDevice(device)) { && isValidDevice(device)) {
return mService.getDeviceMode(device); return service.getDeviceMode(device);
} }
if (mService == null) Log.w(TAG, "Proxy not attached to service"); if (service == null) Log.w(TAG, "Proxy not attached to service");
return MODE_MONAURAL; return MODE_MONAURAL;
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return MODE_MONAURAL; return MODE_MONAURAL;
} finally {
mServiceLock.readLock().unlock();
} }
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
try {
mServiceLock.writeLock().lock();
mService = IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service));
} finally {
mServiceLock.writeLock().unlock();
}
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID,
BluetoothHearingAid.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
try {
mServiceLock.writeLock().lock();
mService = null;
} finally {
mServiceLock.writeLock().unlock();
}
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
return false; return false;

View File

@@ -18,10 +18,8 @@ package android.bluetooth;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.os.Binder;
import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -327,11 +325,6 @@ public final class BluetoothHidDevice implements BluetoothProfile {
} }
} }
private Context mContext;
private ServiceListener mServiceListener;
private volatile IBluetoothHidDevice mService;
private BluetoothAdapter mAdapter;
private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub { private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
private final Executor mExecutor; private final Executor mExecutor;
@@ -385,114 +378,33 @@ public final class BluetoothHidDevice implements BluetoothProfile {
} }
} }
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = private BluetoothAdapter mAdapter;
new IBluetoothStateChangeCallback.Stub() { private final BluetoothProfileConnector<IBluetoothHidDevice> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HID_DEVICE,
public void onBluetoothStateChange(boolean up) { "BluetoothHidDevice", IBluetoothHidDevice.class.getName()) {
Log.d(TAG, "onBluetoothStateChange: up=" + up); @Override
synchronized (mConnection) { public IBluetoothHidDevice getServiceInterface(IBinder service) {
if (up) { return IBluetoothHidDevice.Stub.asInterface(Binder.allowBlocking(service));
try {
if (mService == null) {
Log.d(TAG, "Binding HID Device service...");
doBind();
}
} catch (IllegalStateException e) {
Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ "service: ", e);
} catch (SecurityException e) {
Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ "service: ", e);
}
} else {
Log.d(TAG, "Unbinding service...");
doUnbind();
}
}
}
};
private final ServiceConnection mConnection =
new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "onServiceConnected()");
mService = IBluetoothHidDevice.Stub.asInterface(service);
if (mServiceListener != null) {
mServiceListener.onServiceConnected(
BluetoothProfile.HID_DEVICE, BluetoothHidDevice.this);
}
}
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "onServiceDisconnected()");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
}
} }
}; };
BluetoothHidDevice(Context context, ServiceListener listener) { BluetoothHidDevice(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = listener;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
mProfileConnector.connect(context, listener);
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothHidDevice.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
return false;
}
Log.d(TAG, "Bound to HID Device Service");
return true;
}
void doUnbind() {
if (mService != null) {
mService = null;
try {
mContext.unbindService(mConnection);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to unbind HidDevService", e);
}
}
} }
void close() { void close() {
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
} }
synchronized (mConnection) { private IBluetoothHidDevice getService() {
doUnbind(); return mProfileConnector.getService();
}
mServiceListener = null;
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -509,7 +421,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -526,7 +438,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -583,7 +495,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
throw new IllegalArgumentException("callback parameter cannot be null"); throw new IllegalArgumentException("callback parameter cannot be null");
} }
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
CallbackWrapper cbw = new CallbackWrapper(executor, callback); CallbackWrapper cbw = new CallbackWrapper(executor, callback);
@@ -611,7 +523,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean unregisterApp() { public boolean unregisterApp() {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.unregisterApp(); result = service.unregisterApp();
@@ -636,7 +548,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean sendReport(BluetoothDevice device, int id, byte[] data) { public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.sendReport(device, id, data); result = service.sendReport(device, id, data);
@@ -662,7 +574,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.replyReport(device, type, id, data); result = service.replyReport(device, type, id, data);
@@ -686,7 +598,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean reportError(BluetoothDevice device, byte error) { public boolean reportError(BluetoothDevice device, byte error) {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.reportError(device, error); result = service.reportError(device, error);
@@ -707,7 +619,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* {@hide} * {@hide}
*/ */
public String getUserAppName() { public String getUserAppName() {
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
@@ -733,7 +645,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.connect(device); result = service.connect(device);
@@ -757,7 +669,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
boolean result = false; boolean result = false;
final IBluetoothHidDevice service = mService; final IBluetoothHidDevice service = getService();
if (service != null) { if (service != null) {
try { try {
result = service.disconnect(device); result = service.disconnect(device);

View File

@@ -18,10 +18,7 @@ package android.bluetooth;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -219,39 +216,13 @@ public final class BluetoothHidHost implements BluetoothProfile {
public static final String EXTRA_IDLE_TIME = public static final String EXTRA_IDLE_TIME =
"android.bluetooth.BluetoothHidHost.extra.IDLE_TIME"; "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
private Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private volatile IBluetoothHidHost mService; private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
new IBluetoothStateChangeCallback.Stub() { @Override
public void onBluetoothStateChange(boolean up) { public IBluetoothHidHost getServiceInterface(IBinder service) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
if (!up) {
if (VDBG) Log.d(TAG, "Unbinding service...");
synchronized (mConnection) {
try {
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
@@ -259,57 +230,18 @@ public final class BluetoothHidHost implements BluetoothProfile {
* Create a BluetoothHidHost proxy object for interacting with the local * Create a BluetoothHidHost proxy object for interacting with the local
* Bluetooth Service which handles the InputDevice profile * Bluetooth Service which handles the InputDevice profile
*/ */
/*package*/ BluetoothHidHost(Context context, ServiceListener l) { /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
mProfileConnector.connect(context, listener);
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothHidHost.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
return false;
}
return true;
} }
/*package*/ void close() { /*package*/ void close() {
if (VDBG) log("close()"); if (VDBG) log("close()");
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothHidHost getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -333,7 +265,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.connect(device); return service.connect(device);
@@ -373,7 +305,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -392,7 +324,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -411,7 +343,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -430,7 +362,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -460,7 +392,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -492,7 +424,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -505,26 +437,6 @@ public final class BluetoothHidHost implements BluetoothProfile {
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HID_HOST,
BluetoothHidHost.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.HID_HOST);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON; return mAdapter.getState() == BluetoothAdapter.STATE_ON;
} }
@@ -544,7 +456,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean virtualUnplug(BluetoothDevice device) { public boolean virtualUnplug(BluetoothDevice device) {
if (DBG) log("virtualUnplug(" + device + ")"); if (DBG) log("virtualUnplug(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.virtualUnplug(device); return service.virtualUnplug(device);
@@ -570,7 +482,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean getProtocolMode(BluetoothDevice device) { public boolean getProtocolMode(BluetoothDevice device) {
if (VDBG) log("getProtocolMode(" + device + ")"); if (VDBG) log("getProtocolMode(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getProtocolMode(device); return service.getProtocolMode(device);
@@ -594,7 +506,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
if (DBG) log("setProtocolMode(" + device + ")"); if (DBG) log("setProtocolMode(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.setProtocolMode(device, protocolMode); return service.setProtocolMode(device, protocolMode);
@@ -625,7 +537,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
+ "bufferSize=" + bufferSize); + "bufferSize=" + bufferSize);
} }
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getReport(device, reportType, reportId, bufferSize); return service.getReport(device, reportType, reportId, bufferSize);
@@ -651,7 +563,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean setReport(BluetoothDevice device, byte reportType, String report) { public boolean setReport(BluetoothDevice device, byte reportType, String report) {
if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.setReport(device, reportType, report); return service.setReport(device, reportType, report);
@@ -676,7 +588,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean sendData(BluetoothDevice device, String report) { public boolean sendData(BluetoothDevice device, String report) {
if (DBG) log("sendData(" + device + "), report=" + report); if (DBG) log("sendData(" + device + "), report=" + report);
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.sendData(device, report); return service.sendData(device, report);
@@ -700,7 +612,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean getIdleTime(BluetoothDevice device) { public boolean getIdleTime(BluetoothDevice device) {
if (DBG) log("getIdletime(" + device + ")"); if (DBG) log("getIdletime(" + device + ")");
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getIdleTime(device); return service.getIdleTime(device);
@@ -725,7 +637,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/ */
public boolean setIdleTime(BluetoothDevice device, byte idleTime) { public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime); if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
final IBluetoothHidHost service = mService; final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.setIdleTime(device, idleTime); return service.setIdleTime(device, idleTime);

View File

@@ -17,10 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -44,11 +41,6 @@ public final class BluetoothMap implements BluetoothProfile {
public static final String ACTION_CONNECTION_STATE_CHANGED = public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
private volatile IBluetoothMap mService;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
/** There was an error trying to obtain the state */ /** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1; public static final int STATE_ERROR = -1;
@@ -57,64 +49,23 @@ public final class BluetoothMap implements BluetoothProfile {
/** Connection canceled before completion. */ /** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2; public static final int RESULT_CANCELED = 2;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = private BluetoothAdapter mAdapter;
new IBluetoothStateChangeCallback.Stub() { private final BluetoothProfileConnector<IBluetoothMap> mProfileConnector =
public void onBluetoothStateChange(boolean up) { new BluetoothProfileConnector(this, BluetoothProfile.MAP,
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); "BluetoothMap", IBluetoothMap.class.getName()) {
if (!up) { @Override
if (VDBG) Log.d(TAG, "Unbinding service..."); public IBluetoothMap getServiceInterface(IBinder service) {
synchronized (mConnection) { return IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
/** /**
* Create a BluetoothMap proxy object. * Create a BluetoothMap proxy object.
*/ */
/*package*/ BluetoothMap(Context context, ServiceListener l) { /*package*/ BluetoothMap(Context context, ServiceListener listener) {
if (DBG) Log.d(TAG, "Create BluetoothMap proxy object"); if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothMap.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
return false;
}
return true;
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@@ -132,26 +83,11 @@ public final class BluetoothMap implements BluetoothProfile {
* are ok. * are ok.
*/ */
public synchronized void close() { public synchronized void close() {
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothMap getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -162,7 +98,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public int getState() { public int getState() {
if (VDBG) log("getState()"); if (VDBG) log("getState()");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getState(); return service.getState();
@@ -184,7 +120,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public BluetoothDevice getClient() { public BluetoothDevice getClient() {
if (VDBG) log("getClient()"); if (VDBG) log("getClient()");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getClient(); return service.getClient();
@@ -205,7 +141,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public boolean isConnected(BluetoothDevice device) { public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")"); if (VDBG) log("isConnected(" + device + ")");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.isConnected(device); return service.isConnected(device);
@@ -237,7 +173,7 @@ public final class BluetoothMap implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -278,7 +214,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()"); if (DBG) log("getConnectedDevices()");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -298,7 +234,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()"); if (DBG) log("getDevicesMatchingStates()");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -318,7 +254,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")"); if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -344,7 +280,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -373,7 +309,7 @@ public final class BluetoothMap implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothMap service = mService; final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -386,24 +322,6 @@ public final class BluetoothMap implements BluetoothProfile {
return PRIORITY_OFF; return PRIORITY_OFF;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) log("Proxy object connected");
mService = IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.MAP, BluetoothMap.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) log("Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.MAP);
}
}
};
private static void log(String msg) { private static void log(String msg) {
Log.d(TAG, msg); Log.d(TAG, msg);
} }

View File

@@ -18,11 +18,9 @@ package android.bluetooth;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri; import android.net.Uri;
import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -60,11 +58,6 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String EXTRA_SENDER_CONTACT_NAME = public static final String EXTRA_SENDER_CONTACT_NAME =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
private volatile IBluetoothMapClient mService;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
/** There was an error trying to obtain the state */ /** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1; public static final int STATE_ERROR = -1;
@@ -75,64 +68,23 @@ public final class BluetoothMapClient implements BluetoothProfile {
private static final int UPLOADING_FEATURE_BITMASK = 0x08; private static final int UPLOADING_FEATURE_BITMASK = 0x08;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = private BluetoothAdapter mAdapter;
new IBluetoothStateChangeCallback.Stub() { private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
public void onBluetoothStateChange(boolean up) { new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); "BluetoothMapClient", IBluetoothMapClient.class.getName()) {
if (!up) { @Override
if (VDBG) Log.d(TAG, "Unbinding service..."); public IBluetoothMapClient getServiceInterface(IBinder service) {
synchronized (mConnection) { return IBluetoothMapClient.Stub.asInterface(Binder.allowBlocking(service));
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
/** /**
* Create a BluetoothMapClient proxy object. * Create a BluetoothMapClient proxy object.
*/ */
/*package*/ BluetoothMapClient(Context context, ServiceListener l) { /*package*/ BluetoothMapClient(Context context, ServiceListener listener) {
if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object"); if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object");
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothMapClient.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth MAP MCE Service with " + intent);
return false;
}
return true;
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@@ -150,26 +102,11 @@ public final class BluetoothMapClient implements BluetoothProfile {
* are ok. * are ok.
*/ */
public void close() { public void close() {
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothMapClient getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -179,7 +116,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public boolean isConnected(BluetoothDevice device) { public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")"); if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null) { if (service != null) {
try { try {
return service.isConnected(device); return service.isConnected(device);
@@ -199,7 +136,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE"); if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null) { if (service != null) {
try { try {
return service.connect(device); return service.connect(device);
@@ -221,7 +158,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "disconnect(" + device + ")"); if (DBG) Log.d(TAG, "disconnect(" + device + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -241,7 +178,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG, "getConnectedDevices()"); if (DBG) Log.d(TAG, "getConnectedDevices()");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -262,7 +199,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingStates()"); if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -283,7 +220,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")"); if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -307,7 +244,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")"); if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -336,7 +273,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getPriority(" + device + ")"); if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -365,7 +302,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message, public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
PendingIntent sentIntent, PendingIntent deliveredIntent) { PendingIntent sentIntent, PendingIntent deliveredIntent) {
if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message); if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent); return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent);
@@ -385,7 +322,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
*/ */
public boolean getUnreadMessages(BluetoothDevice device) { public boolean getUnreadMessages(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")"); if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
final IBluetoothMapClient service = mService; final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getUnreadMessages(device); return service.getUnreadMessages(device);
@@ -405,34 +342,16 @@ public final class BluetoothMapClient implements BluetoothProfile {
* MapSupportedFeatures field is set. False is returned otherwise. * MapSupportedFeatures field is set. False is returned otherwise.
*/ */
public boolean isUploadingSupported(BluetoothDevice device) { public boolean isUploadingSupported(BluetoothDevice device) {
final IBluetoothMapClient service = getService();
try { try {
return (mService != null && isEnabled() && isValidDevice(device)) return (service != null && isEnabled() && isValidDevice(device))
&& ((mService.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0); && ((service.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
} }
return false; return false;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothMapClient.Stub.asInterface(service);
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.MAP_CLIENT,
BluetoothMapClient.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.MAP_CLIENT);
}
}
};
private boolean isEnabled() { private boolean isEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true; if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;

View File

@@ -19,10 +19,7 @@ package android.bluetooth;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -121,108 +118,42 @@ public final class BluetoothPan implements BluetoothProfile {
*/ */
public static final int PAN_OPERATION_SUCCESS = 1004; public static final int PAN_OPERATION_SUCCESS = 1004;
private Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter;
private volatile IBluetoothPan mPanService; private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.PAN,
"BluetoothPan", IBluetoothPan.class.getName()) {
@Override
public IBluetoothPan getServiceInterface(IBinder service) {
return IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service));
}
};
/** /**
* Create a BluetoothPan proxy object for interacting with the local * Create a BluetoothPan proxy object for interacting with the local
* Bluetooth Service which handles the Pan profile * Bluetooth Service which handles the Pan profile
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
/*package*/ BluetoothPan(Context context, ServiceListener l) { /*package*/ BluetoothPan(Context context, ServiceListener listener) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
try { mProfileConnector.connect(context, listener);
mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback);
} catch (RemoteException re) {
Log.w(TAG, "Unable to register BluetoothStateChangeCallback", re);
}
if (VDBG) Log.d(TAG, "BluetoothPan() call bindService");
doBind();
}
@UnsupportedAppUsage
boolean doBind() {
Intent intent = new Intent(IBluetoothPan.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth Pan Service with " + intent);
return false;
}
return true;
} }
@UnsupportedAppUsage @UnsupportedAppUsage
/*package*/ void close() { /*package*/ void close() {
if (VDBG) log("close()"); if (VDBG) log("close()");
mProfileConnector.disconnect();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mStateChangeCallback);
} catch (RemoteException re) {
Log.w(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
}
} }
synchronized (mConnection) { private IBluetoothPan getService() {
if (mPanService != null) { return mProfileConnector.getService();
try {
mPanService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
protected void finalize() { protected void finalize() {
close(); close();
} }
private final IBluetoothStateChangeCallback mStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
@Override
public void onBluetoothStateChange(boolean on) {
// Handle enable request to bind again.
Log.d(TAG, "onBluetoothStateChange on: " + on);
if (on) {
try {
if (mPanService == null) {
if (VDBG) Log.d(TAG, "onBluetoothStateChange calling doBind()");
doBind();
}
} catch (IllegalStateException e) {
Log.e(TAG, "onBluetoothStateChange: could not bind to PAN service: ",
e);
} catch (SecurityException e) {
Log.e(TAG, "onBluetoothStateChange: could not bind to PAN service: ",
e);
}
} else {
if (VDBG) Log.d(TAG, "Unbinding service...");
synchronized (mConnection) {
try {
mPanService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
}
};
/** /**
* Initiate connection to a profile of the remote bluetooth device. * Initiate connection to a profile of the remote bluetooth device.
* *
@@ -243,7 +174,7 @@ public final class BluetoothPan implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean connect(BluetoothDevice device) { public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")"); if (DBG) log("connect(" + device + ")");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.connect(device); return service.connect(device);
@@ -284,7 +215,7 @@ public final class BluetoothPan implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -303,7 +234,7 @@ public final class BluetoothPan implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()"); if (VDBG) log("getConnectedDevices()");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -322,7 +253,7 @@ public final class BluetoothPan implements BluetoothProfile {
@Override @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()"); if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -341,7 +272,7 @@ public final class BluetoothPan implements BluetoothProfile {
@Override @Override
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")"); if (VDBG) log("getState(" + device + ")");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -357,7 +288,7 @@ public final class BluetoothPan implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public void setBluetoothTethering(boolean value) { public void setBluetoothTethering(boolean value) {
if (DBG) log("setBluetoothTethering(" + value + ")"); if (DBG) log("setBluetoothTethering(" + value + ")");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
service.setBluetoothTethering(value); service.setBluetoothTethering(value);
@@ -370,7 +301,7 @@ public final class BluetoothPan implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean isTetheringOn() { public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()"); if (VDBG) log("isTetheringOn()");
final IBluetoothPan service = mPanService; final IBluetoothPan service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.isTetheringOn(); return service.isTetheringOn();
@@ -381,25 +312,6 @@ public final class BluetoothPan implements BluetoothProfile {
return false; return false;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
mPanService = IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.PAN,
BluetoothPan.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "BluetoothPAN Proxy object disconnected");
mPanService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.PAN);
}
}
};
@UnsupportedAppUsage @UnsupportedAppUsage
private boolean isEnabled() { private boolean isEnabled() {
return mAdapter.getState() == BluetoothAdapter.STATE_ON; return mAdapter.getState() == BluetoothAdapter.STATE_ON;

View File

@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
@@ -117,29 +118,10 @@ public class BluetoothPbap implements BluetoothProfile {
public void onBluetoothStateChange(boolean up) { public void onBluetoothStateChange(boolean up) {
log("onBluetoothStateChange: up=" + up); log("onBluetoothStateChange: up=" + up);
if (!up) { if (!up) {
log("Unbinding service..."); doUnbind();
synchronized (mConnection) {
try {
if (mService != null) {
mService = null;
mContext.unbindService(mConnection);
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else { } else {
synchronized (mConnection) {
try {
if (mService == null) {
log("Binding service...");
doBind(); doBind();
} }
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
@@ -154,25 +136,51 @@ public class BluetoothPbap implements BluetoothProfile {
if (mgr != null) { if (mgr != null) {
try { try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) { } catch (RemoteException re) {
Log.e(TAG, "", e); Log.e(TAG, "", re);
} }
} }
doBind(); doBind();
} }
boolean doBind() { boolean doBind() {
synchronized (mConnection) {
try {
if (mService == null) {
log("Binding service...");
Intent intent = new Intent(IBluetoothPbap.class.getName()); Intent intent = new Intent(IBluetoothPbap.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); ComponentName comp = intent.resolveSystemService(
mContext.getPackageManager(), 0);
intent.setComponent(comp); intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) { UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent); Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
return false; return false;
} }
}
} catch (SecurityException se) {
Log.e(TAG, "", se);
return false;
}
}
return true; return true;
} }
private void doUnbind() {
synchronized (mConnection) {
if (mService != null) {
log("Unbinding service...");
try {
mContext.unbindService(mConnection);
} catch (IllegalArgumentException ie) {
Log.e(TAG, "", ie);
} finally {
mService = null;
}
}
}
}
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
try { try {
close(); close();
@@ -192,21 +200,11 @@ public class BluetoothPbap implements BluetoothProfile {
if (mgr != null) { if (mgr != null) {
try { try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) { } catch (RemoteException re) {
Log.e(TAG, "", e);
}
}
synchronized (mConnection) {
if (mService != null) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re); Log.e(TAG, "", re);
} }
} }
} doUnbind();
mServiceListener = null; mServiceListener = null;
} }
@@ -312,7 +310,7 @@ public class BluetoothPbap implements BluetoothProfile {
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
log("Proxy object disconnected"); log("Proxy object disconnected");
mService = null; doUnbind();
if (mServiceListener != null) { if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(); mServiceListener.onServiceDisconnected();
} }

View File

@@ -16,10 +16,7 @@
package android.bluetooth; package android.bluetooth;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -42,11 +39,6 @@ public final class BluetoothPbapClient implements BluetoothProfile {
public static final String ACTION_CONNECTION_STATE_CHANGED = public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED"; "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
private volatile IBluetoothPbapClient mService;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
/** There was an error trying to obtain the state */ /** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1; public static final int STATE_ERROR = -1;
@@ -55,72 +47,25 @@ public final class BluetoothPbapClient implements BluetoothProfile {
/** Connection canceled before completion. */ /** Connection canceled before completion. */
public static final int RESULT_CANCELED = 2; public static final int RESULT_CANCELED = 2;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = private BluetoothAdapter mAdapter;
new IBluetoothStateChangeCallback.Stub() { private final BluetoothProfileConnector<IBluetoothPbapClient> mProfileConnector =
public void onBluetoothStateChange(boolean up) { new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT,
if (DBG) { "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) {
Log.d(TAG, "onBluetoothStateChange: PBAP CLIENT up=" + up); @Override
} public IBluetoothPbapClient getServiceInterface(IBinder service) {
if (!up) { return IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
if (VDBG) {
Log.d(TAG, "Unbinding service...");
}
synchronized (mConnection) {
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) {
Log.d(TAG, "Binding service...");
}
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
/** /**
* Create a BluetoothPbapClient proxy object. * Create a BluetoothPbapClient proxy object.
*/ */
BluetoothPbapClient(Context context, ServiceListener l) { BluetoothPbapClient(Context context, ServiceListener listener) {
if (DBG) { if (DBG) {
Log.d(TAG, "Create BluetoothPbapClient proxy object"); Log.d(TAG, "Create BluetoothPbapClient proxy object");
} }
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
private boolean doBind() {
Intent intent = new Intent(IBluetoothPbapClient.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent);
return false;
}
return true;
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@@ -138,26 +83,11 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* are ok. * are ok.
*/ */
public synchronized void close() { public synchronized void close() {
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothPbapClient getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -173,7 +103,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("connect(" + device + ") for PBAP Client."); log("connect(" + device + ") for PBAP Client.");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.connect(device); return service.connect(device);
@@ -198,7 +128,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("disconnect(" + device + ")" + new Exception()); log("disconnect(" + device + ")" + new Exception());
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
service.disconnect(device); service.disconnect(device);
@@ -225,7 +155,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("getConnectedDevices()"); log("getConnectedDevices()");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -250,7 +180,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("getDevicesMatchingStates()"); log("getDevicesMatchingStates()");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -275,7 +205,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("getConnectionState(" + device + ")"); log("getConnectionState(" + device + ")");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -290,29 +220,6 @@ public final class BluetoothPbapClient implements BluetoothProfile {
return BluetoothProfile.STATE_DISCONNECTED; return BluetoothProfile.STATE_DISCONNECTED;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) {
log("Proxy object connected");
}
mService = IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.PBAP_CLIENT,
BluetoothPbapClient.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) {
log("Proxy object disconnected");
}
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP_CLIENT);
}
}
};
private static void log(String msg) { private static void log(String msg) {
Log.d(TAG, msg); Log.d(TAG, msg);
} }
@@ -345,7 +252,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (DBG) { if (DBG) {
log("setPriority(" + device + ", " + priority + ")"); log("setPriority(" + device + ", " + priority + ")");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -378,7 +285,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
if (VDBG) { if (VDBG) {
log("getPriority(" + device + ")"); log("getPriority(" + device + ")");
} }
final IBluetoothPbapClient service = mService; final IBluetoothPbapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);

View File

@@ -0,0 +1,166 @@
/*
* Copyright 2019 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.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
/**
* Connector for Bluetooth profile proxies to bind manager service and
* profile services
* @param <T> The Bluetooth profile interface for this connection.
* @hide
*/
public abstract class BluetoothProfileConnector<T> {
private int mProfileId;
private BluetoothProfile.ServiceListener mServiceListener;
private BluetoothProfile mProfileProxy;
private Context mContext;
private String mProfileName;
private String mServiceName;
private volatile T mService;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
new IBluetoothStateChangeCallback.Stub() {
public void onBluetoothStateChange(boolean up) {
if (up) {
doBind();
} else {
doUnbind();
}
}
};
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
logDebug("Proxy object connected");
mService = getServiceInterface(service);
if (mServiceListener != null) {
mServiceListener.onServiceConnected(mProfileId, mProfileProxy);
}
}
public void onServiceDisconnected(ComponentName className) {
logDebug("Proxy object disconnected");
doUnbind();
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
}
}
};
BluetoothProfileConnector(BluetoothProfile profile, int profileId, String profileName,
String serviceName) {
mProfileId = profileId;
mProfileProxy = profile;
mProfileName = profileName;
mServiceName = serviceName;
}
private boolean doBind() {
synchronized (mConnection) {
if (mService == null) {
logDebug("Binding service...");
try {
Intent intent = new Intent(mServiceName);
ComponentName comp = intent.resolveSystemService(
mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
UserHandle.CURRENT_OR_SELF)) {
logError("Could not bind to Bluetooth Service with " + intent);
return false;
}
} catch (SecurityException se) {
logError("Failed to bind service. " + se);
return false;
}
}
}
return true;
}
private void doUnbind() {
synchronized (mConnection) {
if (mService != null) {
logDebug("Unbinding service...");
try {
mContext.unbindService(mConnection);
} catch (IllegalArgumentException ie) {
logError("Unable to unbind service: " + ie);
} finally {
mService = null;
}
}
}
}
void connect(Context context, BluetoothProfile.ServiceListener listener) {
mContext = context;
mServiceListener = listener;
IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager();
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException re) {
logError("Failed to register state change callback. " + re);
}
}
doBind();
}
void disconnect() {
mServiceListener = null;
IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException re) {
logError("Failed to unregister state change callback" + re);
}
}
doUnbind();
}
T getService() {
return mService;
}
/**
* This abstract function is used to implement method to get the
* connected Bluetooth service interface.
* @param service the connected binder service.
* @return T the binder interface of {@code service}.
* @hide
*/
public abstract T getServiceInterface(IBinder service);
private void logDebug(String log) {
Log.d(mProfileName, log);
}
private void logError(String log) {
Log.e(mProfileName, log);
}
}

View File

@@ -17,10 +17,7 @@
package android.bluetooth; package android.bluetooth;
import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -69,11 +66,6 @@ public final class BluetoothSap implements BluetoothProfile {
public static final String ACTION_CONNECTION_STATE_CHANGED = public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED"; "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
private volatile IBluetoothSap mService;
private final Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
/** /**
* There was an error trying to obtain the state. * There was an error trying to obtain the state.
* *
@@ -95,64 +87,23 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public static final int RESULT_CANCELED = 2; public static final int RESULT_CANCELED = 2;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = private BluetoothAdapter mAdapter;
new IBluetoothStateChangeCallback.Stub() { private final BluetoothProfileConnector<IBluetoothSap> mProfileConnector =
public void onBluetoothStateChange(boolean up) { new BluetoothProfileConnector(this, BluetoothProfile.SAP,
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); "BluetoothSap", IBluetoothSap.class.getName()) {
if (!up) { @Override
if (VDBG) Log.d(TAG, "Unbinding service..."); public IBluetoothSap getServiceInterface(IBinder service) {
synchronized (mConnection) { return IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
} else {
synchronized (mConnection) {
try {
if (mService == null) {
if (VDBG) Log.d(TAG, "Binding service...");
doBind();
}
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
} }
}; };
/** /**
* Create a BluetoothSap proxy object. * Create a BluetoothSap proxy object.
*/ */
/*package*/ BluetoothSap(Context context, ServiceListener l) { /*package*/ BluetoothSap(Context context, ServiceListener listener) {
if (DBG) Log.d(TAG, "Create BluetoothSap proxy object"); if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.connect(context, listener);
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothSap.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
mContext.getUser())) {
Log.e(TAG, "Could not bind to Bluetooth SAP Service with " + intent);
return false;
}
return true;
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@@ -172,26 +123,11 @@ public final class BluetoothSap implements BluetoothProfile {
* @hide * @hide
*/ */
public synchronized void close() { public synchronized void close() {
IBluetoothManager mgr = mAdapter.getBluetoothManager(); mProfileConnector.disconnect();
if (mgr != null) {
try {
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
} catch (Exception e) {
Log.e(TAG, "", e);
}
} }
synchronized (mConnection) { private IBluetoothSap getService() {
if (mService != null) { return mProfileConnector.getService();
try {
mService = null;
mContext.unbindService(mConnection);
} catch (Exception re) {
Log.e(TAG, "", re);
}
}
}
mServiceListener = null;
} }
/** /**
@@ -203,7 +139,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public int getState() { public int getState() {
if (VDBG) log("getState()"); if (VDBG) log("getState()");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getState(); return service.getState();
@@ -226,7 +162,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public BluetoothDevice getClient() { public BluetoothDevice getClient() {
if (VDBG) log("getClient()"); if (VDBG) log("getClient()");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.getClient(); return service.getClient();
@@ -249,7 +185,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public boolean isConnected(BluetoothDevice device) { public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")"); if (VDBG) log("isConnected(" + device + ")");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null) { if (service != null) {
try { try {
return service.isConnected(device); return service.isConnected(device);
@@ -284,7 +220,7 @@ public final class BluetoothSap implements BluetoothProfile {
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) { public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")"); if (DBG) log("disconnect(" + device + ")");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.disconnect(device); return service.disconnect(device);
@@ -305,7 +241,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public List<BluetoothDevice> getConnectedDevices() { public List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()"); if (DBG) log("getConnectedDevices()");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getConnectedDevices(); return service.getConnectedDevices();
@@ -326,7 +262,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()"); if (DBG) log("getDevicesMatchingStates()");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled()) { if (service != null && isEnabled()) {
try { try {
return service.getDevicesMatchingConnectionStates(states); return service.getDevicesMatchingConnectionStates(states);
@@ -347,7 +283,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public int getConnectionState(BluetoothDevice device) { public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")"); if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getConnectionState(device); return service.getConnectionState(device);
@@ -372,7 +308,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public boolean setPriority(BluetoothDevice device, int priority) { public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")"); if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
if (priority != BluetoothProfile.PRIORITY_OFF if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON) { && priority != BluetoothProfile.PRIORITY_ON) {
@@ -398,7 +334,7 @@ public final class BluetoothSap implements BluetoothProfile {
*/ */
public int getPriority(BluetoothDevice device) { public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")"); if (VDBG) log("getPriority(" + device + ")");
final IBluetoothSap service = mService; final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) { if (service != null && isEnabled() && isValidDevice(device)) {
try { try {
return service.getPriority(device); return service.getPriority(device);
@@ -411,24 +347,6 @@ public final class BluetoothSap implements BluetoothProfile {
return PRIORITY_OFF; return PRIORITY_OFF;
} }
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) log("Proxy object connected");
mService = IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service));
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this);
}
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) log("Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.SAP);
}
}
};
private static void log(String msg) { private static void log(String msg) {
Log.d(TAG, msg); Log.d(TAG, msg);
} }

View File

@@ -1094,11 +1094,21 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
public void unbindBluetoothProfileService(int bluetoothProfile, public void unbindBluetoothProfileService(int bluetoothProfile,
IBluetoothProfileServiceConnection proxy) { IBluetoothProfileServiceConnection proxy) {
synchronized (mProfileServices) { synchronized (mProfileServices) {
ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile)); Integer profile = new Integer(bluetoothProfile);
ProfileServiceConnections psc = mProfileServices.get(profile);
if (psc == null) { if (psc == null) {
return; return;
} }
psc.removeProxy(proxy); psc.removeProxy(proxy);
if (psc.isEmpty()) {
// All prxoies are disconnected, unbind with the service.
try {
mContext.unbindService(psc);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
}
mProfileServices.remove(profile);
}
} }
} }
@@ -1255,6 +1265,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mProxies.kill(); mProxies.kill();
} }
private boolean isEmpty() {
return mProxies.getRegisteredCallbackCount() == 0;
}
@Override @Override
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
// remove timeout message // remove timeout message