Loading core/java/android/bluetooth/BluetoothHearingAid.java +71 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; Loading Loading @@ -378,6 +379,76 @@ public final class BluetoothHearingAid implements BluetoothProfile { } } /** * Select a connected device as active. * * The active device selection is per profile. An active device's * purpose is profile-specific. For example, Hearing Aid audio * streaming is to the active Hearing Aid device. If a remote device * is not connected, it cannot be selected as active. * * <p> This API returns false in scenarios like the profile on the * device is not connected or Bluetooth is not turned on. * When this API returns true, it is guaranteed that the * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted * with the active device. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission. * * @param device the remote Bluetooth device. Could be null to clear * the active device and stop streaming audio to a Bluetooth device. * @return false on immediate error, true otherwise * @hide */ public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); try { mServiceLock.readLock().lock(); if (mService != null && isEnabled() && ((device == null) || isValidDevice(device))) { mService.setActiveDevice(device); return true; } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } finally { mServiceLock.readLock().unlock(); } } /** * Check whether the device is active. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * permission. * * @return the connected device that is active or null if no device * is active * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isActiveDevice(@Nullable BluetoothDevice device) { if (VDBG) log("isActiveDevice()"); try { mServiceLock.readLock().lock(); if (mService != null && isEnabled() && ((device == null) || isValidDevice(device))) { return mService.isActiveDevice(device); } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } finally { mServiceLock.readLock().unlock(); } } /** * Set priority of the profile * Loading core/res/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,8 @@ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -115,6 +116,8 @@ public class BluetoothEventManager { new ActiveDeviceChangedHandler()); addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler); mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler); Loading Loading @@ -434,6 +437,8 @@ public class BluetoothEventManager { bluetoothProfile = BluetoothProfile.A2DP; } else if (Objects.equals(action, BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { bluetoothProfile = BluetoothProfile.HEADSET; } else if (Objects.equals(action, BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED)) { bluetoothProfile = BluetoothProfile.HEARING_AID; } else { Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action); return; Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +25 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // Active device state private boolean mIsActiveDeviceA2dp = false; private boolean mIsActiveDeviceHeadset = false; private boolean mIsActiveDeviceHearingAid = false; /** * Describes the current device and profile for logging. Loading Loading @@ -436,6 +437,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> result = true; } } HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); if ((hearingAidProfile != null) && isConnectedProfile(hearingAidProfile)) { if (hearingAidProfile.setActiveDevice(getDevice())) { Log.i(TAG, "OnPreferenceClickListener: Hearing Aid active device=" + this); result = true; } } return result; } Loading Loading @@ -501,6 +509,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> changed = (mIsActiveDeviceHeadset != isActive); mIsActiveDeviceHeadset = isActive; break; case BluetoothProfile.HEARING_AID: changed = (mIsActiveDeviceHearingAid != isActive); mIsActiveDeviceHearingAid = isActive; break; default: Log.w(TAG, "onActiveDeviceChanged: unknown profile " + bluetoothProfile + " isActive " + isActive); Loading @@ -524,6 +536,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return mIsActiveDeviceA2dp; case BluetoothProfile.HEADSET: return mIsActiveDeviceHeadset; case BluetoothProfile.HEARING_AID: return mIsActiveDeviceHearingAid; default: Log.w(TAG, "getActiveDevice: unknown profile " + bluetoothProfile); break; Loading Loading @@ -615,6 +629,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (headsetProfile != null) { mIsActiveDeviceHeadset = mDevice.equals(headsetProfile.getActiveDevice()); } HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); if (hearingAidProfile != null) { mIsActiveDeviceHearingAid = hearingAidProfile.isActiveDevice(mDevice); } } /** Loading Loading @@ -945,6 +963,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean profileConnected = false; // at least one profile is connected boolean a2dpNotConnected = false; // A2DP is preferred but not connected boolean hfpNotConnected = false; // HFP is preferred but not connected boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected for (LocalBluetoothProfile profile : getProfiles()) { int connectionStatus = getProfileConnectionState(profile); Loading @@ -966,6 +985,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } else if ((profile instanceof HeadsetProfile) || (profile instanceof HfpClientProfile)) { hfpNotConnected = true; } else if (profile instanceof HearingAidProfile) { hearingAidNotConnected = true; } } break; Loading Loading @@ -998,6 +1019,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only } } if (!hearingAidNotConnected && mIsActiveDeviceHearingAid) { activeDeviceString = activeDeviceStringsArray[1]; return mContext.getString(R.string.bluetooth_connected, activeDeviceString); } if (profileConnected) { if (a2dpNotConnected && hfpNotConnected) { Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +11 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,17 @@ public class HearingAidProfile implements LocalBluetoothProfile { return mService.getConnectionState(device); } public boolean setActiveDevice(BluetoothDevice device) { if (mService == null) return false; mService.setActiveDevice(device); return true; } public boolean isActiveDevice(BluetoothDevice device) { if (mService == null) return false; return mService.isActiveDevice(device); } public boolean isPreferred(BluetoothDevice device) { if (mService == null) return false; return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; Loading Loading
core/java/android/bluetooth/BluetoothHearingAid.java +71 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; Loading Loading @@ -378,6 +379,76 @@ public final class BluetoothHearingAid implements BluetoothProfile { } } /** * Select a connected device as active. * * The active device selection is per profile. An active device's * purpose is profile-specific. For example, Hearing Aid audio * streaming is to the active Hearing Aid device. If a remote device * is not connected, it cannot be selected as active. * * <p> This API returns false in scenarios like the profile on the * device is not connected or Bluetooth is not turned on. * When this API returns true, it is guaranteed that the * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted * with the active device. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission. * * @param device the remote Bluetooth device. Could be null to clear * the active device and stop streaming audio to a Bluetooth device. * @return false on immediate error, true otherwise * @hide */ public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); try { mServiceLock.readLock().lock(); if (mService != null && isEnabled() && ((device == null) || isValidDevice(device))) { mService.setActiveDevice(device); return true; } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } finally { mServiceLock.readLock().unlock(); } } /** * Check whether the device is active. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * permission. * * @return the connected device that is active or null if no device * is active * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isActiveDevice(@Nullable BluetoothDevice device) { if (VDBG) log("isActiveDevice()"); try { mServiceLock.readLock().lock(); if (mService != null && isEnabled() && ((device == null) || isValidDevice(device))) { return mService.isActiveDevice(device); } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } finally { mServiceLock.readLock().unlock(); } } /** * Set priority of the profile * Loading
core/res/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,8 @@ android:name="android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -115,6 +116,8 @@ public class BluetoothEventManager { new ActiveDeviceChangedHandler()); addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler()); mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter, null, mReceiverHandler); mContext.registerReceiver(mProfileBroadcastReceiver, mProfileIntentFilter, null, mReceiverHandler); Loading Loading @@ -434,6 +437,8 @@ public class BluetoothEventManager { bluetoothProfile = BluetoothProfile.A2DP; } else if (Objects.equals(action, BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) { bluetoothProfile = BluetoothProfile.HEADSET; } else if (Objects.equals(action, BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED)) { bluetoothProfile = BluetoothProfile.HEARING_AID; } else { Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action); return; Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +25 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> // Active device state private boolean mIsActiveDeviceA2dp = false; private boolean mIsActiveDeviceHeadset = false; private boolean mIsActiveDeviceHearingAid = false; /** * Describes the current device and profile for logging. Loading Loading @@ -436,6 +437,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> result = true; } } HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); if ((hearingAidProfile != null) && isConnectedProfile(hearingAidProfile)) { if (hearingAidProfile.setActiveDevice(getDevice())) { Log.i(TAG, "OnPreferenceClickListener: Hearing Aid active device=" + this); result = true; } } return result; } Loading Loading @@ -501,6 +509,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> changed = (mIsActiveDeviceHeadset != isActive); mIsActiveDeviceHeadset = isActive; break; case BluetoothProfile.HEARING_AID: changed = (mIsActiveDeviceHearingAid != isActive); mIsActiveDeviceHearingAid = isActive; break; default: Log.w(TAG, "onActiveDeviceChanged: unknown profile " + bluetoothProfile + " isActive " + isActive); Loading @@ -524,6 +536,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return mIsActiveDeviceA2dp; case BluetoothProfile.HEADSET: return mIsActiveDeviceHeadset; case BluetoothProfile.HEARING_AID: return mIsActiveDeviceHearingAid; default: Log.w(TAG, "getActiveDevice: unknown profile " + bluetoothProfile); break; Loading Loading @@ -615,6 +629,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (headsetProfile != null) { mIsActiveDeviceHeadset = mDevice.equals(headsetProfile.getActiveDevice()); } HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); if (hearingAidProfile != null) { mIsActiveDeviceHearingAid = hearingAidProfile.isActiveDevice(mDevice); } } /** Loading Loading @@ -945,6 +963,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean profileConnected = false; // at least one profile is connected boolean a2dpNotConnected = false; // A2DP is preferred but not connected boolean hfpNotConnected = false; // HFP is preferred but not connected boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected for (LocalBluetoothProfile profile : getProfiles()) { int connectionStatus = getProfileConnectionState(profile); Loading @@ -966,6 +985,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } else if ((profile instanceof HeadsetProfile) || (profile instanceof HfpClientProfile)) { hfpNotConnected = true; } else if (profile instanceof HearingAidProfile) { hearingAidNotConnected = true; } } break; Loading Loading @@ -998,6 +1019,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only } } if (!hearingAidNotConnected && mIsActiveDeviceHearingAid) { activeDeviceString = activeDeviceStringsArray[1]; return mContext.getString(R.string.bluetooth_connected, activeDeviceString); } if (profileConnected) { if (a2dpNotConnected && hfpNotConnected) { Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +11 −0 Original line number Diff line number Diff line Loading @@ -134,6 +134,17 @@ public class HearingAidProfile implements LocalBluetoothProfile { return mService.getConnectionState(device); } public boolean setActiveDevice(BluetoothDevice device) { if (mService == null) return false; mService.setActiveDevice(device); return true; } public boolean isActiveDevice(BluetoothDevice device) { if (mService == null) return false; return mService.isActiveDevice(device); } public boolean isPreferred(BluetoothDevice device) { if (mService == null) return false; return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; Loading