diff options
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothHapClient.java')
-rw-r--r-- | framework/java/android/bluetooth/BluetoothHapClient.java | 488 |
1 files changed, 383 insertions, 105 deletions
diff --git a/framework/java/android/bluetooth/BluetoothHapClient.java b/framework/java/android/bluetooth/BluetoothHapClient.java index 992e906963..2b245bcb41 100644 --- a/framework/java/android/bluetooth/BluetoothHapClient.java +++ b/framework/java/android/bluetooth/BluetoothHapClient.java @@ -19,10 +19,13 @@ package android.bluetooth; import static android.bluetooth.BluetoothUtils.getSyncTimeout; +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; +import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.content.AttributionSource; import android.content.Context; @@ -33,8 +36,11 @@ import android.util.Log; import com.android.modules.utils.SynchronousResultReceiver; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; @@ -44,7 +50,9 @@ import java.util.concurrent.TimeoutException; * <p>BluetoothHapClient is a proxy object for controlling the Bluetooth HAP * Service client via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the * BluetoothHapClient proxy object. + * @hide */ +@SystemApi public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable { private static final String TAG = "BluetoothHapClient"; private static final boolean DBG = false; @@ -53,6 +61,126 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable private CloseGuard mCloseGuard; /** + * This class provides callbacks mechanism for the BluetoothHapClient profile. + * + * @hide + */ + @SystemApi + public interface Callback { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST, + BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST, + BluetoothStatusCodes.REASON_REMOTE_REQUEST, + BluetoothStatusCodes.REASON_SYSTEM_POLICY, + BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED, + BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED, + BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG, + BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX, + BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID, + }) + @interface Status {} + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + PRESET_INFO_REASON_ALL_PRESET_INFO, + PRESET_INFO_REASON_PRESET_INFO_UPDATE, + PRESET_INFO_REASON_PRESET_DELETED, + PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED, + PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE, + }) + @interface PresetInfoReason {} + + /** + * Invoked to inform about HA device's currently active preset. + * + * @param device remote device, + * @param presetIndex the currently active preset index. + * + * @hide + */ + @SystemApi + void onActivePresetChanged(@NonNull BluetoothDevice device, int presetIndex); + + /** + * Invoked inform about the result of a failed preset change attempt. + * + * @param device remote device, + * @param statusCode failure reason. + * + * @hide + */ + @SystemApi + void onSelectActivePresetFailed(@NonNull BluetoothDevice device, @Status int statusCode); + + /** + * Invoked to inform about the result of a failed preset change attempt. + * + * The implementation will try to restore the state for every device back to original + * + * @param hapGroupId valid HAP group ID, + * @param statusCode failure reason. + * + * @hide + */ + @SystemApi + void onSelectActivePresetForGroupFailed(int hapGroupId, @Status int statusCode); + + /** + * Invoked to inform about the preset list changes. + * + * @param device remote device, + * @param presetInfoList a list of all preset information on the target device + * @param statusCode reason for the preset list change + * + * @hide + */ + @SystemApi + void onPresetInfoChanged(@NonNull BluetoothDevice device, + @NonNull List<BluetoothHapPresetInfo> presetInfoList, + @Status int statusCode); + + /** + * Invoked to inform about HA device's feature set. + * + * @param device remote device + * @param hapFeatures the feature set integer with these possible bit numbers + * set: {@link #FEATURE_BIT_NUM_TYPE_MONAURAL}, {@link #FEATURE_BIT_NUM_TYPE_BANDED}, + * {@link #FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS}, + * {@link #FEATURE_BIT_NUM_INDEPENDENT_PRESETS}, {@link #FEATURE_BIT_NUM_DYNAMIC_PRESETS}, + * {@link #FEATURE_BIT_NUM_WRITABLE_PRESETS}. + * + * @hide + */ + void onHapFeaturesAvailable(@NonNull BluetoothDevice device, int hapFeatures); + + /** + * Invoked to inform about the failed preset rename attempt. + * + * @param device remote device + * @param status Failure reason code. + * @hide + */ + @SystemApi + void onSetPresetNameFailed(@NonNull BluetoothDevice device, @Status int status); + + /** + * Invoked to inform about the failed preset rename attempt. + * + * The implementation will try to restore the state for every device back to original + * + * @param hapGroupId valid HAP group ID, + * @param status Failure reason code. + * @hide + */ + @SystemApi + void onSetPresetNameForGroupFailed(int hapGroupId, @Status int status); + } + + /** * Intent used to broadcast the change in connection state of the Hearing Access Profile Client * service. Please note that in the binaural case, there will be two different LE devices for * the left and right side and each device will have their own connection state changes. @@ -67,9 +195,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_HAP_CONNECTION_STATE_CHANGED = "android.bluetooth.action.HAP_CONNECTION_STATE_CHANGED"; @@ -84,9 +217,9 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> * <li> {@link #EXTRA_HAP_FEATURES} - Supported features map. </li> * </ul> - * * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, @@ -461,6 +594,63 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable } /** + * Register a {@link Callback} that will be invoked during the + * operation of this profile. + * + * Repeated registration of the same <var>callback</var> object will have no effect after + * the first call to this method, even when the <var>executor</var> is different. API caller + * would have to call {@link #unregisterCallback(Callback)} with + * the same callback object before registering it again. + * + * @param executor an {@link Executor} to execute given callback + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException if a null executor, sink, or callback is given + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void registerCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + if (executor == null) { + throw new IllegalArgumentException("executor cannot be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + if (DBG) log("registerCallback"); + throw new UnsupportedOperationException("Not Implemented"); + } + + /** + * Unregister the specified {@link Callback}. + * <p>The same {@link Callback} object used when calling + * {@link #registerCallback(Executor, Callback)} must be used. + * + * <p>Callbacks are automatically unregistered when application process goes away + * + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException when callback is null or when no callback is registered + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void unregisterCallback(@NonNull Callback callback) { + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + if (DBG) log("unregisterCallback"); + throw new UnsupportedOperationException("Not Implemented"); + } + + /** * Set connection policy of the profile * * <p> The device should already be paired. @@ -472,6 +662,7 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * @return true if connectionPolicy is set, false on error * @hide */ + @SystemApi @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, @@ -510,8 +701,12 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * @return connection policy of the device * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothHapClient service = getService(); @@ -533,10 +728,15 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * @hide */ - @Override + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + @Override public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) Log.d(TAG, "getConnectedDevices()"); final IBluetoothHapClient service = getService(); @@ -558,10 +758,15 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * @hide */ - @Override + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + @Override public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( @NonNull int[] states) { if (VDBG) Log.d(TAG, "getDevicesMatchingConnectionStates()"); @@ -584,10 +789,15 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable /** * {@inheritDoc} + * @hide */ - @Override + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + @Override public @BluetoothProfile.BtProfileState int getConnectionState( @NonNull BluetoothDevice device) { if (VDBG) Log.d(TAG, "getConnectionState(" + device + ")"); @@ -627,7 +837,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public int getHapGroup(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); final int defaultValue = HAP_GROUP_UNAVAILABLE; @@ -647,44 +860,73 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable } /** - * Gets the currently active preset for a HA device + * Gets the currently active preset for a HA device. * * @param device is the device for which we want to set the active preset * @return active preset index * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean getActivePresetIndex(@NonNull BluetoothDevice device) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public int getActivePresetIndex(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); - final boolean defaultValue = false; + final int defaultValue = PRESET_INDEX_UNAVAILABLE; if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); - service.getActivePresetIndex(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } + // TODO(b/216639668) + // try { + // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + // service.getActivePresetIndex(device, mAttributionSource, recv); + // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + // } catch (RemoteException | TimeoutException e) { + // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + // } } return defaultValue; } /** + * Get the currently active preset info for a remote device. + * + * @param device is the device for which we want to get the preset name + * @return currently active preset info if selected, null if preset info is not available + * for the remote device + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public @Nullable BluetoothHapPresetInfo getActivePresetInfo(@NonNull BluetoothDevice device) { + // TODO(b/216639668) + return null; + } + + /** * Selects the currently active preset for a HA device * + * On success, {@link Callback#onActivePresetChanged(BluetoothDevice, int)} will be called with + * reason code {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} + * On failure, {@link Callback#onSelectActivePresetFailed(BluetoothDevice, int)} will be called. + * * @param device is the device for which we want to set the active preset * @param presetIndex is an index of one of the available presets - * @return true if valid request was sent, false otherwise * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean selectActivePreset(@NonNull BluetoothDevice device, int presetIndex) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void selectPreset(@NonNull BluetoothDevice device, int presetIndex) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -692,31 +934,39 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.selectActivePreset(device, presetIndex, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** - * Selects the currently active preset for a HA device group. + * Selects the currently active preset for a Hearing Aid device group. * * <p> This group call may replace multiple device calls if those are part of the * valid HAS group. Note that binaural HA devices may or may not support group. * + * On success, {@link Callback#onActivePresetChanged(BluetoothDevice, int)} will be called + * for each device within the group with reason code + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} + * On failure, {@link Callback#onSelectActivePresetFailed(BluetoothDevice, int)} will be called + * for each device within the group. + * * @param groupId is the device group identifier for which want to set the active preset * @param presetIndex is an index of one of the available presets - * @return true if valid group request was sent, false otherwise * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean groupSelectActivePreset(int groupId, int presetIndex) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void selectPresetForGroup(int groupId, int presetIndex) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -724,14 +974,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled()) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.groupSelectActivePreset(groupId, presetIndex, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** @@ -741,13 +991,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * does not necessarily mean a higher preset index. * * @param device is the device for which we want to set the active preset - * @return true if valid request was sent, false otherwise * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean nextActivePreset(@NonNull BluetoothDevice device) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void switchToNextPreset(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -755,14 +1006,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.nextActivePreset(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** @@ -774,13 +1025,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * valid HAS group. Note that binaural HA devices may or may not support group. * * @param groupId is the device group identifier for which want to set the active preset - * @return true if valid group request was sent, false otherwise * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean groupNextActivePreset(int groupId) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void switchToNextPresetForGroup(int groupId) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -788,14 +1040,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled()) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.groupNextActivePreset(groupId, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** @@ -805,13 +1057,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * does not necessarily mean a lower preset index. * * @param device is the device for which we want to set the active preset - * @return true if valid request was sent, false otherwise * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean previousActivePreset(@NonNull BluetoothDevice device) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void switchToPreviousPreset(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -819,14 +1072,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.previousActivePreset(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** @@ -838,13 +1091,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * valid HAS group. Note that binaural HA devices may or may not support group. * * @param groupId is the device group identifier for which want to set the active preset - * @return true if valid group request was sent, false otherwise * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean groupPreviousActivePreset(int groupId) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void switchToPreviousPresetForGroup(int groupId) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -852,14 +1106,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled()) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.groupPreviousActivePreset(groupId, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** @@ -867,54 +1121,62 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * * @param device is the device for which we want to get the preset name * @param presetIndex is an index of one of the available presets - * @return true if valid request was sent, false otherwise + * @return preset info * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean getPresetInfo(@NonNull BluetoothDevice device, int presetIndex) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public @NonNull BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device, + int presetIndex) { final IBluetoothHapClient service = getService(); - final boolean defaultValue = false; + final BluetoothHapPresetInfo.Builder builder = new BluetoothHapPresetInfo.Builder(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); - service.getPresetInfo(device, presetIndex, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } + // TODO(b/216639668) + // try { + // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + // service.getPresetInfo(device, presetIndex, mAttributionSource, recv); + // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(builder); + // } catch (RemoteException | TimeoutException e) { + // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + // } } - return defaultValue; + return builder.build(); } /** - * Requests all presets info + * Get all preset info for a particular device * * @param device is the device for which we want to get all presets info - * @return true if request was processed, false otherwise + * @return a list of all known preset info * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean getAllPresetsInfo(@NonNull BluetoothDevice device) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public @NonNull List<BluetoothHapPresetInfo> getAllPresetInfo(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); - final boolean defaultValue = false; + final List<BluetoothHapPresetInfo> defaultValue = new ArrayList<BluetoothHapPresetInfo>(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { - try { - final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); - service.getAllPresetsInfo(device, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); - } catch (RemoteException | TimeoutException e) { - Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); - } + // TODO(b/216639668) + // try { + // final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + // service.getAllPresetsInfo(device, mAttributionSource, recv); + // return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + // } catch (RemoteException | TimeoutException e) { + // Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + // } } return defaultValue; } @@ -927,8 +1189,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable * @hide */ @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) public boolean getFeatures(@NonNull BluetoothDevice device) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; @@ -948,21 +1212,28 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable } /** - * Sets the preset name + * Sets the preset name for a particular device * - * <p> Note that the name length is restricted to 30 characters. + * <p> Note that the name length is restricted to 40 characters. + * + * On success, {@link Callback#onPresetInfoChanged(BluetoothDevice, List, int)} + * with a new name will be called and reason code + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} + * On failure, {@link Callback#onSetPresetNameFailed(BluetoothDevice, int)} will be called. * * @param device is the device for which we want to get the preset name * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - * @return true if valid request was sent, false otherwise + * @param name is a new name for a preset, maximum length is 40 characters * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean setPresetName(@NonNull BluetoothDevice device, int presetIndex, - @NonNull String name) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void setPresetName(@NonNull BluetoothDevice device, int presetIndex, + @NonNull String name) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -970,31 +1241,38 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled() && isValidDevice(device)) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.setPresetName(device, presetIndex, name, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } /** - * Sets the preset name + * Sets the name for a hearing aid preset. + * + * <p> Note that the name length is restricted to 40 characters. * - * <p> Note that the name length is restricted to 30 characters. + * On success, {@link Callback#onPresetInfoChanged(BluetoothDevice, List, int)} + * with a new name will be called for each device within the group with reason code + * {@link BluetoothStatusCodes#REASON_LOCAL_APP_REQUEST} + * On failure, {@link Callback#onSetPresetNameForGroupFailed(int, int)} will be invoked * * @param groupId is the device group identifier * @param presetIndex is an index of one of the available presets - * @param name is a new name for a preset - * @return true if valid request was sent, false otherwise + * @param name is a new name for a preset, maximum length is 40 characters * @hide */ + @SystemApi @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) - public boolean groupSetPresetName(int groupId, int presetIndex, @NonNull String name) { + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED + }) + public void setPresetNameForGroup(int groupId, int presetIndex, @NonNull String name) { final IBluetoothHapClient service = getService(); final boolean defaultValue = false; if (service == null) { @@ -1002,14 +1280,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable if (DBG) log(Log.getStackTraceString(new Throwable())); } else if (isEnabled()) { try { + // TODO(b/216639668) final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); service.groupSetPresetName(groupId, presetIndex, name, mAttributionSource, recv); - return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return defaultValue; } private boolean isEnabled() { |