From 05f4bc40743654ea501b18d70ee162a08b81b35c Mon Sep 17 00:00:00 2001 From: Jack He Date: Wed, 3 Jan 2018 12:13:26 -0800 Subject: [PATCH] HFP: Add APIs for set and get active device (1/3) 1. Call BluetoothHeadset.setActiveDevice(BluetoothDevice device) to set a connected HFP/HSP device as active. 2. Listen for BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED intent that will contain the latest active device (in EXTRA_DEVICE field). If the active device could not be changed, the EXTRA_DEVICE field could be null. 3. If setActiveDevice() is NOT in-progress, BluetoothA2dp.getActiveDevice() can be used. If setActiveDevice() is in-progress, the result is undefined. 4. BluetoothHeadset.setActiveDevice() could be called by some other parts of the system, so interested parties should always listen for BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED intents and prepared for active device updates. Bug: 68951996 Test: manual Change-Id: I22ca639a04fed7bf17df59c405ddeda90dafb8ff --- .../android/bluetooth/BluetoothHeadset.java | 88 +++++++++++++++++++ core/res/AndroidManifest.xml | 2 + 2 files changed, 90 insertions(+) diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 838d3153d54cf..55a6b4c6b4d4e 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -16,6 +16,7 @@ package android.bluetooth; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -93,6 +94,23 @@ public final class BluetoothHeadset implements BluetoothProfile { public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED"; + /** + * Intent used to broadcast the selection of a connected device as active. + * + *

This intent will have one extra: + *

+ * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_ACTIVE_DEVICE_CHANGED = + "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED"; /** * Intent used to broadcast that the headset has posted a @@ -982,6 +1000,76 @@ public final class BluetoothHeadset implements BluetoothProfile { return false; } + /** + * Select a connected device as active. + * + * The active device selection is per profile. An active device's + * purpose is profile-specific. For example, in HFP and HSP profiles, + * it is the device used for phone call audio. If a remote device is not + * connected, it cannot be selected as active. + * + *

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. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device, could be null if phone call audio should not be + * streamed to a headset + * @return false on immediate error, true otherwise + * @hide + */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) + public boolean setActiveDevice(@Nullable BluetoothDevice device) { + if (DBG) { + Log.d(TAG, "setActiveDevice: " + device); + } + final IBluetoothHeadset service = mService; + if (service != null && isEnabled() && (device == null || isValidDevice(device))) { + try { + return service.setActiveDevice(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return false; + } + + /** + * Get the connected device that is active. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * permission. + * + * @return the connected device that is active or null if no device + * is active. + * @hide + */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH) + public BluetoothDevice getActiveDevice() { + if (VDBG) { + Log.d(TAG, "getActiveDevice"); + } + final IBluetoothHeadset service = mService; + if (service != null && isEnabled()) { + try { + return service.getActiveDevice(); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + } + return null; + } + /** * check if in-band ringing is supported for this platform. * diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e33c822dfc7da..4b2ae06eff2f2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -158,6 +158,8 @@ android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" /> +