summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterService.java2
-rw-r--r--android/app/src/com/android/bluetooth/btservice/PhonePolicy.java10
-rw-r--r--android/app/src/com/android/bluetooth/btservice/RemoteDevices.java6
-rw-r--r--android/app/src/com/android/bluetooth/btservice/ServiceFactory.java5
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java3
-rw-r--r--android/app/src/com/android/bluetooth/hap/HapClientService.java765
-rw-r--r--android/app/src/com/android/bluetooth/hap/HapClientStackEvent.java43
-rw-r--r--android/app/src/com/android/bluetooth/hap/HapClientStateMachine.java8
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hap/HapClientTest.java513
-rw-r--r--floss/OWNERS1
-rw-r--r--floss/build/Dockerfile76
-rw-r--r--floss/build/README.md23
-rwxr-xr-xfloss/build/build-in-docker.py163
-rwxr-xr-xfloss/build/docker-build-image.py147
-rwxr-xr-xfloss/build/llvm-rename.sh57
-rw-r--r--framework/api/system-current.txt1
-rw-r--r--framework/java/android/bluetooth/BluetoothHapClient.java677
-rw-r--r--framework/java/android/bluetooth/BluetoothHeadset.java17
-rw-r--r--framework/java/android/bluetooth/BluetoothUuid.java8
-rw-r--r--system/Android.bp2
-rw-r--r--system/binder/Android.bp1
-rw-r--r--system/binder/android/bluetooth/IBluetoothHapClient.aidl44
-rw-r--r--system/binder/android/bluetooth/IBluetoothHapClientCallback.aidl39
-rw-r--r--system/blueberry/facade/topshim/facade.proto3
-rw-r--r--system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py5
-rw-r--r--system/blueberry/tests/gd/rust/topshim/facade/suspend_test.py42
-rw-r--r--system/bta/ag/bta_ag_act.cc1
-rw-r--r--system/bta/has/has_client.cc12
-rw-r--r--system/bta/has/has_types.h2
-rw-r--r--system/btif/src/btif_dm.cc3
-rw-r--r--system/build/dpkg/libchrome-822064/debian/README.Debian1
-rw-r--r--system/build/dpkg/libchrome-822064/debian/changelog5
-rw-r--r--system/build/dpkg/libchrome-822064/debian/compat1
-rw-r--r--system/build/dpkg/libchrome-822064/debian/control28
-rwxr-xr-xsystem/build/dpkg/libchrome-822064/debian/install_headers.sh50
-rw-r--r--system/build/dpkg/libchrome-822064/debian/libchrome.install4
-rw-r--r--system/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch37
-rw-r--r--system/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch34
-rw-r--r--system/build/dpkg/libchrome-822064/debian/patches/series3
-rwxr-xr-xsystem/build/dpkg/libchrome-822064/debian/rules38
-rwxr-xr-xsystem/build/dpkg/libchrome-822064/gen-src-pkg.sh60
-rw-r--r--system/build/dpkg/libchrome/debian/changelog6
-rw-r--r--system/build/dpkg/libchrome/debian/control3
-rwxr-xr-xsystem/build/dpkg/libchrome/debian/install_headers.sh11
-rw-r--r--system/build/dpkg/libchrome/debian/libchrome.install.docker5
-rw-r--r--system/build/dpkg/libchrome/debian/patches/0001-Fix-build-issues-on-930012.patch37
-rw-r--r--system/build/dpkg/libchrome/debian/patches/0001-Remove-absl-from-pkgconfig.patch (renamed from system/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch)0
-rw-r--r--system/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch36
-rw-r--r--system/build/dpkg/libchrome/debian/patches/series3
-rwxr-xr-xsystem/build/dpkg/libchrome/debian/rules8
-rwxr-xr-xsystem/build/dpkg/libchrome/gen-src-pkg.sh27
-rw-r--r--system/build/dpkg/modp_b64/debian/modp-b64.install.docker3
-rwxr-xr-xsystem/build/dpkg/modp_b64/gen-src-pkg.sh9
-rwxr-xr-xsystem/gd/cert/run_topshim5
-rw-r--r--system/gd/rust/topshim/facade/src/adapter_service.rs8
-rw-r--r--system/gd/rust/topshim/src/btif.rs4
-rw-r--r--system/include/hardware/bt_has.h7
-rw-r--r--system/stack/btm/btm_iso_impl.h15
-rw-r--r--system/stack/test/btm_iso_test.cc22
-rw-r--r--system/vendor_libs/test_vendor_lib/net/posix/posix_async_socket.cc2
60 files changed, 1899 insertions, 1252 deletions
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index 0ccf2ac7c1..1cb8f08cb0 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -1090,7 +1090,7 @@ public class AdapterService extends Service {
* @return true if any profile is enabled, false otherwise
*/
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- private boolean isAnyProfileEnabled(BluetoothDevice device) {
+ boolean isAnyProfileEnabled(BluetoothDevice device) {
if (mA2dpService != null && mA2dpService.getConnectionPolicy(device)
> BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index 50aff4ae61..f1cef7af66 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -43,6 +43,7 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.hap.HapClientService;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.hid.HidHostService;
@@ -296,6 +297,7 @@ class PhonePolicy {
mFactory.getCsipSetCoordinatorService();
VolumeControlService volumeControlService =
mFactory.getVolumeControlService();
+ HapClientService hapClientService = mFactory.getHapClientService();
// Set profile priorities only for the profiles discovered on the remote device.
// This avoids needless auto-connect attempts to profiles non-existent on the remote device
@@ -364,6 +366,14 @@ class PhonePolicy {
mAdapterService.getDatabase().setProfileConnectionPolicy(device,
BluetoothProfile.VOLUME_CONTROL, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
+
+ if ((hapClientService != null) && Utils.arrayContains(uuids,
+ BluetoothUuid.HAS) && (hapClientService.getConnectionPolicy(device)
+ == BluetoothProfile.CONNECTION_POLICY_UNKNOWN)) {
+ debugLog("setting hearing access profile priority for device " + device);
+ mAdapterService.getDatabase().setProfileConnectionPolicy(device,
+ BluetoothProfile.HAP_CLIENT, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ }
}
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index 4f9f7bb990..2d8915388d 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -847,6 +847,12 @@ final class RemoteDevices {
if (sAdapterService.getConnectionState(device) == 0) {
resetBatteryLevel(device);
}
+ if (!sAdapterService.isAnyProfileEnabled(device)) {
+ DeviceProperties deviceProp = getDeviceProperties(device);
+ if (deviceProp != null) {
+ deviceProp.setBondingInitiatedLocally(false);
+ }
+ }
debugLog(
"aclStateChangeCallback: Adapter State: " + BluetoothAdapter.nameForState(state)
+ " Disconnected: " + device
diff --git a/android/app/src/com/android/bluetooth/btservice/ServiceFactory.java b/android/app/src/com/android/bluetooth/btservice/ServiceFactory.java
index 6842dc0de5..f9256ad2a1 100644
--- a/android/app/src/com/android/bluetooth/btservice/ServiceFactory.java
+++ b/android/app/src/com/android/bluetooth/btservice/ServiceFactory.java
@@ -19,6 +19,7 @@ package com.android.bluetooth.btservice;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.avrcp.AvrcpTargetService;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.hap.HapClientService;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.hid.HidDeviceService;
@@ -73,4 +74,8 @@ public class ServiceFactory {
public VolumeControlService getVolumeControlService() {
return VolumeControlService.getVolumeControlService();
}
+
+ public HapClientService getHapClientService() {
+ return HapClientService.getHapClientService();
+ }
}
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index ef1a979ca9..d2e8b758da 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -167,8 +167,7 @@ public class GattService extends ProfileService {
UUID.fromString("00001850-0000-1000-8000-00805F9B34FB"), // PACS
UUID.fromString("0000184E-0000-1000-8000-00805F9B34FB"), // ASCS
UUID.fromString("0000184F-0000-1000-8000-00805F9B34FB"), // BASS
- /* FIXME: Not known yet, using a placeholder instead. */
- UUID.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE"), // HAP
+ UUID.fromString("00001854-0000-1000-8000-00805F9B34FB"), // HAP
};
/**
diff --git a/android/app/src/com/android/bluetooth/hap/HapClientService.java b/android/app/src/com/android/bluetooth/hap/HapClientService.java
index f082b8fe82..4a44daf8b7 100644
--- a/android/app/src/com/android/bluetooth/hap/HapClientService.java
+++ b/android/app/src/com/android/bluetooth/hap/HapClientService.java
@@ -20,14 +20,18 @@ package com.android.bluetooth.hap;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
+import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
+
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHapPresetInfo;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothHapClient;
+import android.bluetooth.IBluetoothHapClientCallback;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -35,6 +39,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.ParcelUuid;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
import android.util.Log;
import com.android.bluetooth.Utils;
@@ -48,6 +54,7 @@ import com.android.modules.utils.SynchronousResultReceiver;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
@@ -64,6 +71,7 @@ public class HapClientService extends ProfileService {
// Upper limit of all HearingAccess devices: Bonded or Connected
private static final int MAX_HEARING_ACCESS_STATE_MACHINES = 10;
+ private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000;
private static HapClientService sHapClient;
private final Map<BluetoothDevice, HapClientStateMachine> mStateMachines =
new HashMap<>();
@@ -76,10 +84,13 @@ public class HapClientService extends ProfileService {
private final Map<BluetoothDevice, Integer> mDeviceCurrentPresetMap = new HashMap<>();
private final Map<BluetoothDevice, Integer> mDeviceFeaturesMap = new HashMap<>();
- private final Map<BluetoothDevice, ArrayList<BluetoothHapPresetInfo>> mPresetsMap =
+ private final Map<BluetoothDevice, List<BluetoothHapPresetInfo>> mPresetsMap =
new HashMap<>();
@VisibleForTesting
+ RemoteCallbackList<IBluetoothHapClientCallback> mCallbacks;
+
+ @VisibleForTesting
ServiceFactory mFactory = new ServiceFactory();
private static synchronized void setHapClient(HapClientService instance) {
@@ -148,10 +159,6 @@ public class HapClientService extends ProfileService {
mStateMachinesThread = new HandlerThread("HapClientService.StateMachines");
mStateMachinesThread.start();
- mDeviceCurrentPresetMap.clear();
- mDeviceFeaturesMap.clear();
- mPresetsMap.clear();
-
// Setup broadcast receivers
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -162,12 +169,14 @@ public class HapClientService extends ProfileService {
mConnectionStateChangedReceiver = new ConnectionStateChangedReceiver();
registerReceiver(mConnectionStateChangedReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
- // Mark service as started
- setHapClient(this);
+ mCallbacks = new RemoteCallbackList<IBluetoothHapClientCallback>();
// Initialize native interface
mHapClientNativeInterface.init();
+ // Mark service as started
+ setHapClient(this);
+
return true;
}
@@ -181,10 +190,6 @@ public class HapClientService extends ProfileService {
return true;
}
- // Cleanup GATT interface
- mHapClientNativeInterface.cleanup();
- mHapClientNativeInterface = null;
-
// Marks service as stopped
setHapClient(null);
@@ -203,20 +208,29 @@ public class HapClientService extends ProfileService {
mStateMachines.clear();
}
- mDeviceCurrentPresetMap.clear();
- mDeviceFeaturesMap.clear();
- mPresetsMap.clear();
-
if (mStateMachinesThread != null) {
try {
mStateMachinesThread.quitSafely();
- mStateMachinesThread.join();
+ mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
mStateMachinesThread = null;
} catch (InterruptedException e) {
// Do not rethrow as we are shutting down anyway
}
}
+ // Cleanup GATT interface
+ mHapClientNativeInterface.cleanup();
+ mHapClientNativeInterface = null;
+
+ // Cleanup the internals
+ mDeviceCurrentPresetMap.clear();
+ mDeviceFeaturesMap.clear();
+ mPresetsMap.clear();
+
+ if (mCallbacks != null) {
+ mCallbacks.kill();
+ }
+
// Clear AdapterService
mAdapterService = null;
@@ -345,8 +359,7 @@ public class HapClientService extends ProfileService {
* @return true on success, otherwise false
*/
public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
- enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
+ enforceBluetoothPrivilegedPermission(this);
if (DBG) {
Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
}
@@ -437,8 +450,7 @@ public class HapClientService extends ProfileService {
* @return true if hearing access service client successfully connected, false otherwise
*/
public boolean connect(BluetoothDevice device) {
- enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
+ enforceBluetoothPrivilegedPermission(this);
if (DBG) {
Log.d(TAG, "connect(): " + device);
}
@@ -474,8 +486,7 @@ public class HapClientService extends ProfileService {
* @return true if hearing access service client successfully disconnected, false otherwise
*/
public boolean disconnect(BluetoothDevice device) {
- enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
+ enforceBluetoothPrivilegedPermission(this);
if (DBG) {
Log.d(TAG, "disconnect(): " + device);
}
@@ -542,12 +553,33 @@ public class HapClientService extends ProfileService {
* Gets the currently active preset index for a HA device
*
* @param device is the device for which we want to get the currently active preset
- * @return true if valid request was sent, false otherwise
+ * @return active preset index
*/
- public boolean getActivePresetIndex(BluetoothDevice device) {
- notifyActivePresetIndex(device, mDeviceCurrentPresetMap.getOrDefault(device,
- BluetoothHapClient.PRESET_INDEX_UNAVAILABLE));
- return true;
+ public int getActivePresetIndex(BluetoothDevice device) {
+ return mDeviceCurrentPresetMap.getOrDefault(device,
+ BluetoothHapClient.PRESET_INDEX_UNAVAILABLE);
+ }
+
+ /**
+ * Gets the currently active preset info for a HA device
+ *
+ * @param device is the device for which we want to get the currently active preset info
+ * @return active preset info
+ */
+ public BluetoothHapPresetInfo getActivePresetInfo(BluetoothDevice device) {
+ int index = getActivePresetIndex(device);
+ if (index == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return null;
+
+ List<BluetoothHapPresetInfo> current_presets = mPresetsMap.get(device);
+ if (current_presets != null) {
+ for (BluetoothHapPresetInfo preset : current_presets) {
+ if (preset.getIndex() == index) {
+ return preset;
+ }
+ }
+ }
+
+ return null;
}
/**
@@ -555,12 +587,25 @@ public class HapClientService extends ProfileService {
*
* @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
*/
- public boolean selectActivePreset(BluetoothDevice device, int presetIndex) {
- if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false;
+ public void selectPreset(BluetoothDevice device, int presetIndex) {
+ if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSelectActivePresetFailed(device,
+ BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ return;
+ }
+
mHapClientNativeInterface.selectActivePreset(device, presetIndex);
- return true;
}
/**
@@ -568,64 +613,70 @@ public class HapClientService extends ProfileService {
*
* @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
*/
- public boolean groupSelectActivePreset(int groupId, int presetIndex) {
- if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE
- || groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- return false;
+ public void selectPresetForGroup(int groupId, int presetIndex) {
+ int status = BluetoothStatusCodes.ERROR_UNKNOWN;
+
+ if ((presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE)
+ || (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID)) {
+ if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) {
+ status = BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX;
+ } else {
+ status = BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID;
+ }
+
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSelectActivePresetForGroupFailed(groupId,
+ BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ return;
}
mHapClientNativeInterface.groupSelectActivePreset(groupId, presetIndex);
- return true;
}
/**
* Sets the next preset as a currently active preset for a HA device
*
* @param device is the device for which we want to set the active preset
- * @return true if valid request was sent, false otherwise
*/
- public boolean nextActivePreset(BluetoothDevice device) {
+ public void switchToNextPreset(BluetoothDevice device) {
mHapClientNativeInterface.nextActivePreset(device);
- return true;
}
/**
* Sets the next preset as a currently active preset for a HA device 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
*/
- public boolean groupNextActivePreset(int groupId) {
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return false;
-
+ public void switchToNextPresetForGroup(int groupId) {
mHapClientNativeInterface.groupNextActivePreset(groupId);
- return true;
}
/**
* Sets the previous preset as a currently active preset for a HA device
*
* @param device is the device for which we want to set the active preset
- * @return true if valid request was sent, false otherwise
*/
- public boolean previousActivePreset(BluetoothDevice device) {
+ public void switchToPreviousPreset(BluetoothDevice device) {
mHapClientNativeInterface.previousActivePreset(device);
- return true;
}
/**
* Sets the previous preset as a currently active preset for a HA device 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
*/
- public boolean groupPreviousActivePreset(int groupId) {
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return false;
-
+ public void switchToPreviousPresetForGroup(int groupId) {
mHapClientNativeInterface.groupPreviousActivePreset(groupId);
- return true;
}
/**
@@ -633,92 +684,270 @@ public class HapClientService extends ProfileService {
*
* @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 a preset Info corresponding to the requested preset index
*/
- public boolean getPresetInfo(BluetoothDevice device, int presetIndex) {
- if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false;
- mHapClientNativeInterface.getPresetInfo(device, presetIndex);
- return true;
+ public BluetoothHapPresetInfo getPresetInfo(BluetoothDevice device, int presetIndex) {
+ BluetoothHapPresetInfo defaultValue = new BluetoothHapPresetInfo.Builder().build();
+
+ if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return defaultValue;
+
+ List<BluetoothHapPresetInfo> current_presets = mPresetsMap.get(device);
+ if (current_presets != null) {
+ for (BluetoothHapPresetInfo preset : current_presets) {
+ if (preset.getIndex() == presetIndex) {
+ return preset;
+ }
+ }
+ }
+
+ return defaultValue;
}
/**
* Requests all presets info
*
* @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 presets Info
*/
- public boolean getAllPresetsInfo(BluetoothDevice device) {
+ public List<BluetoothHapPresetInfo> getAllPresetInfo(BluetoothDevice device) {
if (mPresetsMap.containsKey(device)) {
- notifyPresets(device, BluetoothHapClient.PRESET_INFO_REASON_ALL_PRESET_INFO,
- mPresetsMap.get(device));
- return true;
+ return mPresetsMap.get(device);
}
- return false;
+ return Collections.emptyList();
}
/**
* Requests features
*
* @param device is the device for which we want to get features
- * @return true if request was processed, false otherwise
+ * @return integer with feature bits set
*/
- public boolean getFeatures(BluetoothDevice device) {
+ public int getFeatures(BluetoothDevice device) {
if (mDeviceFeaturesMap.containsKey(device)) {
- notifyFeatures(device, mDeviceFeaturesMap.get(device));
- return true;
+ return mDeviceFeaturesMap.get(device);
}
- return false;
+ return 0x00;
}
- private void notifyPresets(BluetoothDevice device, int infoReason,
- ArrayList<BluetoothHapPresetInfo> presets) {
- Intent intent = null;
+ private int stackEventPresetInfoReasonToProfileStatus(int statusCode) {
+ switch (statusCode) {
+ case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO:
+ return BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST;
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE:
+ return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED:
+ return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED:
+ return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE:
+ return BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST;
+ default:
+ return BluetoothStatusCodes.ERROR_UNKNOWN;
+ }
+ }
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO);
- if (intent != null) {
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO_REASON, infoReason);
- intent.putParcelableArrayListExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO, presets);
- sendBroadcast(intent, BLUETOOTH_PRIVILEGED);
+ private void notifyPresetInfoChanged(BluetoothDevice device, int infoReason) {
+ List current_presets = mPresetsMap.get(device);
+ if (current_presets == null) return;
+
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onPresetInfoChanged(device, current_presets,
+ stackEventPresetInfoReasonToProfileStatus(infoReason));
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
}
}
- private void notifyPresets(int groupId, int infoReason,
- ArrayList<BluetoothHapPresetInfo> presets) {
- Intent intent = null;
+ private void notifyPresetInfoForGroupChanged(int groupId, int infoReason) {
+ List<BluetoothDevice> all_group_devices = getGroupDevices(groupId);
+ for (BluetoothDevice dev : all_group_devices) {
+ notifyPresetInfoChanged(dev, infoReason);
+ }
+ }
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO);
- if (intent != null) {
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_GROUP_ID, groupId);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO_REASON, infoReason);
- intent.putParcelableArrayListExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO, presets);
- sendBroadcast(intent, BLUETOOTH_PRIVILEGED);
+ private void notifyFeaturesAvailable(BluetoothDevice device, int features) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onHapFeaturesAvailable(device, features);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
}
}
- private void notifyFeatures(BluetoothDevice device, int features) {
- Intent intent = null;
+ private void notifyActivePresetChanged(BluetoothDevice device, int presetIndex) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onActivePresetChanged(device, presetIndex);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ }
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_DEVICE_FEATURES);
- if (intent != null) {
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_FEATURES, features);
- sendBroadcast(intent, BLUETOOTH_PRIVILEGED);
+ private void notifyActivePresetChangedForGroup(int groupId, int presetIndex) {
+ List<BluetoothDevice> all_group_devices = getGroupDevices(groupId);
+ for (BluetoothDevice dev : all_group_devices) {
+ notifyActivePresetChanged(dev, presetIndex);
+ }
+ }
+
+ private int stackEventStatusToProfileStatus(int statusCode) {
+ switch (statusCode) {
+ case HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED:
+ return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
+ case HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED:
+ return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
+ case HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE:
+ return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
+ case HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH:
+ return BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG;
+ case HapClientStackEvent.STATUS_INVALID_PRESET_INDEX:
+ return BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX;
+ case HapClientStackEvent.STATUS_GROUP_OPERATION_NOT_SUPPORTED:
+ return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
+ case HapClientStackEvent.STATUS_PROCEDURE_ALREADY_IN_PROGRESS:
+ return BluetoothStatusCodes.ERROR_UNKNOWN;
+ default:
+ return BluetoothStatusCodes.ERROR_UNKNOWN;
+ }
+ }
+
+ private void notifySelectActivePresetFailed(BluetoothDevice device, int statusCode) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSelectActivePresetFailed(device,
+ stackEventStatusToProfileStatus(statusCode));
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ }
+
+ private void notifySelectActivePresetForGroupFailed(int groupId, int statusCode) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSelectActivePresetForGroupFailed(groupId,
+ stackEventStatusToProfileStatus(statusCode));
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
}
}
+ private void notifySetPresetNameFailed(BluetoothDevice device, int statusCode) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSetPresetNameFailed(device,
+ stackEventStatusToProfileStatus(statusCode));
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ }
+
+ private void notifySetPresetNameForGroupFailed(int groupId, int statusCode) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSetPresetNameForGroupFailed(groupId,
+ stackEventStatusToProfileStatus(statusCode));
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ }
+
+ private boolean isPresetIndexValid(BluetoothDevice device, int presetIndex) {
+ if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false;
+
+ List<BluetoothHapPresetInfo> device_presets = mPresetsMap.get(device);
+ if (device_presets != null) {
+ for (BluetoothHapPresetInfo preset : device_presets) {
+ if (preset.getIndex() == presetIndex) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isPresetIndexValid(int groupId, int presetIndex) {
+ List<BluetoothDevice> all_group_devices = getGroupDevices(groupId);
+ for (BluetoothDevice device : all_group_devices) {
+ if (!isPresetIndexValid(device, presetIndex)) return false;
+ }
+ return true;
+ }
+
+
+ private boolean isGroupIdValid(int groupId) {
+ if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return false;
+
+ CsipSetCoordinatorService csipClient = mFactory.getCsipSetCoordinatorService();
+ if (csipClient != null) {
+ List<Integer> groups = csipClient.getAllGroupIds(BluetoothUuid.CAP);
+ return groups.contains(groupId);
+ }
+ return true;
+ }
+
/**
* Sets the preset name
*
* @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
*/
- public boolean setPresetName(BluetoothDevice device, int presetIndex, String name) {
- if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false;
+ public void setPresetName(BluetoothDevice device, int presetIndex, String name) {
+ if (!isPresetIndexValid(device, presetIndex)) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSetPresetNameFailed(device,
+ BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ return;
+ }
+ // WARNING: We should check cache if preset exists and is writable, but then we would still
+ // need a way to trigger this action with an invalid index or on a non-writable
+ // preset for tests purpose.
mHapClientNativeInterface.setPresetName(device, presetIndex, name);
- return true;
}
/**
@@ -727,13 +956,33 @@ public class HapClientService extends ProfileService {
* @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
*/
- public boolean groupSetPresetName(int groupId, int presetIndex, String name) {
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return false;
- if (presetIndex == BluetoothHapClient.PRESET_INDEX_UNAVAILABLE) return false;
+ public void setPresetNameForGroup(int groupId, int presetIndex, String name) {
+ int status = BluetoothStatusCodes.SUCCESS;
+
+ if (!isGroupIdValid(groupId)) {
+ status = BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID;
+ }
+ if (!isPresetIndexValid(groupId, presetIndex)) {
+ status = BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX;
+ }
+ if (status != BluetoothStatusCodes.SUCCESS) {
+ if (mCallbacks != null) {
+ int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onSetPresetNameForGroupFailed(groupId,
+ status);
+ } catch (RemoteException e) {
+ continue;
+ }
+ }
+ mCallbacks.finishBroadcast();
+ }
+ return;
+ }
+
mHapClientNativeInterface.groupSetPresetName(groupId, presetIndex, name);
- return true;
}
@Override
@@ -750,30 +999,16 @@ public class HapClientService extends ProfileService {
HapClientStackEvent.FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS);
}
- void notifyActivePresetIndex(BluetoothDevice device, int presetIndex) {
- Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, presetIndex);
- sendBroadcast(intent, BLUETOOTH_PRIVILEGED);
- }
-
- void notifyActivePresetIndex(int groupId, int presetIndex) {
- Intent intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_GROUP_ID, groupId);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, presetIndex);
- sendBroadcast(intent, BLUETOOTH_PRIVILEGED);
- }
-
void updateDevicePresetsCache(BluetoothDevice device, int infoReason,
- ArrayList<BluetoothHapPresetInfo> presets) {
+ List<BluetoothHapPresetInfo> presets) {
switch (infoReason) {
- case BluetoothHapClient.PRESET_INFO_REASON_ALL_PRESET_INFO:
+ case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO:
mPresetsMap.put(device, presets);
break;
- case BluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_UPDATE:
- case BluetoothHapClient.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED:
- case BluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE: {
- ArrayList current_presets = mPresetsMap.get(device);
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE:
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED:
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE: {
+ List current_presets = mPresetsMap.get(device);
if (current_presets != null) {
ListIterator<BluetoothHapPresetInfo> iter = current_presets.listIterator();
for (BluetoothHapPresetInfo new_preset : presets) {
@@ -791,8 +1026,8 @@ public class HapClientService extends ProfileService {
}
break;
- case BluetoothHapClient.PRESET_INFO_REASON_PRESET_DELETED: {
- ArrayList current_presets = mPresetsMap.get(device);
+ case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED: {
+ List current_presets = mPresetsMap.get(device);
if (current_presets != null) {
ListIterator<BluetoothHapPresetInfo> iter = current_presets.listIterator();
for (BluetoothHapPresetInfo new_preset : presets) {
@@ -812,6 +1047,19 @@ public class HapClientService extends ProfileService {
}
}
+ private List<BluetoothDevice> getGroupDevices(int groupId) {
+ List<BluetoothDevice> devices = new ArrayList<>();
+
+ // TODO: Fix missing CSIS service API to decouple from LeAudioService
+ LeAudioService le_audio_service = mFactory.getLeAudioService();
+ if (le_audio_service != null) {
+ if (groupId != BluetoothLeAudio.GROUP_ID_INVALID) {
+ devices = le_audio_service.getGroupDevices(groupId);
+ }
+ }
+ return devices;
+ }
+
/**
* Handle messages from native (JNI) to Java
*
@@ -845,7 +1093,7 @@ public class HapClientService extends ProfileService {
if (device != null) {
mDeviceFeaturesMap.put(device, features);
- notifyFeatures(device, features);
+ notifyFeaturesAvailable(device, features);
}
} return;
@@ -855,36 +1103,25 @@ public class HapClientService extends ProfileService {
if (device != null) {
mDeviceCurrentPresetMap.put(device, currentPresetIndex);
- notifyActivePresetIndex(device, currentPresetIndex);
+ notifyActivePresetChanged(device, currentPresetIndex);
} else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- // TODO: Fix missing CSIS service API to decouple from LeAudioService
- LeAudioService le_audio_service = mFactory.getLeAudioService();
- if (le_audio_service != null) {
- int group_id = le_audio_service.getGroupId(device);
- if (group_id != BluetoothLeAudio.GROUP_ID_INVALID) {
- List<BluetoothDevice> all_group_devices =
- le_audio_service.getGroupDevices(group_id);
- for (BluetoothDevice dev : all_group_devices) {
- mDeviceCurrentPresetMap.put(dev, currentPresetIndex);
- }
- }
+ List<BluetoothDevice> all_group_devices = getGroupDevices(groupId);
+ for (BluetoothDevice dev : all_group_devices) {
+ mDeviceCurrentPresetMap.put(dev, currentPresetIndex);
}
- notifyActivePresetIndex(groupId, currentPresetIndex);
+ notifyActivePresetChangedForGroup(groupId, currentPresetIndex);
}
} return;
case (HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECT_ERROR): {
- int statusCode = stackEvent.valueInt1;
int groupId = stackEvent.valueInt2;
-
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET_SELECT_ERROR);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, statusCode);
+ int statusCode = stackEvent.valueInt1;
if (device != null) {
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+ notifySelectActivePresetFailed(device, statusCode);
} else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_GROUP_ID, groupId);
+ notifySelectActivePresetForGroupFailed(groupId, statusCode);
}
} break;
@@ -896,22 +1133,14 @@ public class HapClientService extends ProfileService {
if (device != null) {
updateDevicePresetsCache(device, infoReason, presets);
- notifyPresets(device, infoReason, presets);
+ notifyPresetInfoChanged(device, infoReason);
} else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- // TODO: Fix missing CSIS service API to decouple from LeAudioService
- LeAudioService le_audio_service = mFactory.getLeAudioService();
- if (le_audio_service != null) {
- int group_id = le_audio_service.getGroupId(device);
- if (group_id != BluetoothLeAudio.GROUP_ID_INVALID) {
- List<BluetoothDevice> all_group_devices =
- le_audio_service.getGroupDevices(group_id);
- for (BluetoothDevice dev : all_group_devices) {
- updateDevicePresetsCache(dev, infoReason, presets);
- }
- }
+ List<BluetoothDevice> all_group_devices = getGroupDevices(groupId);
+ for (BluetoothDevice dev : all_group_devices) {
+ updateDevicePresetsCache(dev, infoReason, presets);
}
- notifyPresets(groupId, infoReason, presets);
+ notifyPresetInfoForGroupChanged(groupId, infoReason);
}
} return;
@@ -919,33 +1148,18 @@ public class HapClientService extends ProfileService {
case (HapClientStackEvent.EVENT_TYPE_ON_PRESET_NAME_SET_ERROR): {
int statusCode = stackEvent.valueInt1;
int presetIndex = stackEvent.valueInt2;
-
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_PRESET_NAME_SET_ERROR);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, presetIndex);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, statusCode);
+ int groupId = stackEvent.valueInt3;
if (device != null) {
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- } else {
- int groupId = stackEvent.valueInt3;
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_GROUP_ID, groupId);
+ notifySetPresetNameFailed(device, statusCode);
+ } else if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ notifySetPresetNameForGroupFailed(groupId, statusCode);
}
} break;
case (HapClientStackEvent.EVENT_TYPE_ON_PRESET_INFO_ERROR): {
- int statusCode = stackEvent.valueInt1;
- int presetIndex = stackEvent.valueInt2;
-
- intent = new Intent(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO_GET_ERROR);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, presetIndex);
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, statusCode);
-
- if (device != null) {
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
- } else {
- int groupId = stackEvent.valueInt3;
- intent.putExtra(BluetoothHapClient.EXTRA_HAP_GROUP_ID, groupId);
- }
+ // Used only to report back on hidden API calls used for testing.
+ Log.d(TAG, stackEvent.toString());
} break;
default:
@@ -1014,36 +1228,6 @@ public class HapClientService extends ProfileService {
}
@Override
- public void connect(BluetoothDevice device, AttributionSource source,
- SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.connect(device);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
- }
- }
-
- @Override
- public void disconnect(BluetoothDevice device, AttributionSource source,
- SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.disconnect(device);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
- }
- }
-
- @Override
public void getConnectedDevices(AttributionSource source,
SynchronousResultReceiver receiver) {
try {
@@ -1122,7 +1306,7 @@ public class HapClientService extends ProfileService {
public void getActivePresetIndex(BluetoothDevice device, AttributionSource source,
SynchronousResultReceiver receiver) {
try {
- boolean defaultValue = false;
+ int defaultValue = BluetoothHapClient.PRESET_INDEX_UNAVAILABLE;
HapClientService service = getService(source);
if (service != null) {
defaultValue = service.getActivePresetIndex(device);
@@ -1134,13 +1318,13 @@ public class HapClientService extends ProfileService {
}
@Override
- public void getHapGroup(BluetoothDevice device, AttributionSource source,
- SynchronousResultReceiver receiver) {
+ public void getActivePresetInfo(BluetoothDevice device,
+ AttributionSource source, SynchronousResultReceiver receiver) {
try {
- int defaultValue = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ BluetoothHapPresetInfo defaultValue = null;
HapClientService service = getService(source);
if (service != null) {
- defaultValue = service.getHapGroup(device);
+ defaultValue = service.getActivePresetInfo(device);
}
receiver.send(defaultValue);
} catch (RuntimeException e) {
@@ -1149,13 +1333,13 @@ public class HapClientService extends ProfileService {
}
@Override
- public void selectActivePreset(BluetoothDevice device, int presetIndex,
- AttributionSource source, SynchronousResultReceiver receiver) {
+ public void getHapGroup(BluetoothDevice device, AttributionSource source,
+ SynchronousResultReceiver receiver) {
try {
- boolean defaultValue = false;
+ int defaultValue = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
HapClientService service = getService(source);
if (service != null) {
- defaultValue = service.selectActivePreset(device, presetIndex);
+ defaultValue = service.getHapGroup(device);
}
receiver.send(defaultValue);
} catch (RuntimeException e) {
@@ -1164,76 +1348,51 @@ public class HapClientService extends ProfileService {
}
@Override
- public void groupSelectActivePreset(int groupId, int presetIndex,
- AttributionSource source, SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.groupSelectActivePreset(groupId, presetIndex);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
+ public void selectPreset(BluetoothDevice device, int presetIndex,
+ AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.selectPreset(device, presetIndex);
}
}
@Override
- public void nextActivePreset(BluetoothDevice device, AttributionSource source,
- SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.nextActivePreset(device);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
+ public void selectPresetForGroup(int groupId, int presetIndex, AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.selectPresetForGroup(groupId, presetIndex);
}
}
@Override
- public void groupNextActivePreset(int groupId, AttributionSource source,
- SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.groupNextActivePreset(groupId);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
+ public void switchToNextPreset(BluetoothDevice device, AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.switchToNextPreset(device);
}
}
@Override
- public void previousActivePreset(BluetoothDevice device, AttributionSource source,
- SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.previousActivePreset(device);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
+ public void switchToNextPresetForGroup(int groupId, AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.switchToNextPresetForGroup(groupId);
}
}
@Override
- public void groupPreviousActivePreset(int groupId, AttributionSource source, SynchronousResultReceiver receiver) {
- try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.groupPreviousActivePreset(groupId);
- }
- receiver.send(defaultValue);
- } catch (RuntimeException e) {
- receiver.propagateException(e);
+ public void switchToPreviousPreset(BluetoothDevice device, AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.switchToPreviousPreset(device);
+ }
+ }
+
+ @Override
+ public void switchToPreviousPresetForGroup(int groupId, AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.switchToPreviousPresetForGroup(groupId);
}
}
@@ -1241,7 +1400,7 @@ public class HapClientService extends ProfileService {
public void getPresetInfo(BluetoothDevice device, int presetIndex,
AttributionSource source, SynchronousResultReceiver receiver) {
try {
- boolean defaultValue = false;
+ BluetoothHapPresetInfo defaultValue = new BluetoothHapPresetInfo.Builder().build();
HapClientService service = getService(source);
if (service != null) {
defaultValue = service.getPresetInfo(device, presetIndex);
@@ -1253,12 +1412,13 @@ public class HapClientService extends ProfileService {
}
@Override
- public void getAllPresetsInfo(BluetoothDevice device, AttributionSource source, SynchronousResultReceiver receiver) {
+ public void getAllPresetInfo(BluetoothDevice device, AttributionSource source,
+ SynchronousResultReceiver receiver) {
try {
- boolean defaultValue = false;
+ List<BluetoothHapPresetInfo> defaultValue = new ArrayList<>();
HapClientService service = getService(source);
if (service != null) {
- defaultValue = service.getAllPresetsInfo(device);
+ defaultValue = service.getAllPresetInfo(device);
}
receiver.send(defaultValue);
} catch (RuntimeException e) {
@@ -1267,9 +1427,10 @@ public class HapClientService extends ProfileService {
}
@Override
- public void getFeatures(BluetoothDevice device, AttributionSource source, SynchronousResultReceiver receiver) {
+ public void getFeatures(BluetoothDevice device, AttributionSource source,
+ SynchronousResultReceiver receiver) {
try {
- boolean defaultValue = false;
+ int defaultValue = 0x00;
HapClientService service = getService(source);
if (service != null) {
defaultValue = service.getFeatures(device);
@@ -1282,29 +1443,51 @@ public class HapClientService extends ProfileService {
@Override
public void setPresetName(BluetoothDevice device, int presetIndex, String name,
+ AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.setPresetName(device, presetIndex, name);
+ }
+ }
+
+ @Override
+ public void setPresetNameForGroup(int groupId, int presetIndex, String name,
+ AttributionSource source) {
+ HapClientService service = getService(source);
+ if (service != null) {
+ service.setPresetNameForGroup(groupId, presetIndex, name);
+ }
+ }
+
+ @Override
+ public void registerCallback(IBluetoothHapClientCallback callback,
AttributionSource source, SynchronousResultReceiver receiver) {
+ HapClientService service = getService(source);
+ if (service == null) {
+ throw new IllegalStateException("Service is unavailable");
+ }
+
+ enforceBluetoothPrivilegedPermission(service);
try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.setPresetName(device, presetIndex, name);
- }
- receiver.send(defaultValue);
+ service.mCallbacks.register(callback);
+ receiver.send(null);
} catch (RuntimeException e) {
receiver.propagateException(e);
}
}
@Override
- public void groupSetPresetName(int groupId, int presetIndex, String name,
+ public void unregisterCallback(IBluetoothHapClientCallback callback,
AttributionSource source, SynchronousResultReceiver receiver) {
+ HapClientService service = getService(source);
+ if (service == null) {
+ throw new IllegalStateException("Service is unavailable");
+ }
+
+ enforceBluetoothPrivilegedPermission(service);
try {
- boolean defaultValue = false;
- HapClientService service = getService(source);
- if (service != null) {
- defaultValue = service.groupSetPresetName(groupId, presetIndex, name);
- }
- receiver.send(defaultValue);
+ service.mCallbacks.unregister(callback);
+ receiver.send(null);
} catch (RuntimeException e) {
receiver.propagateException(e);
}
diff --git a/android/app/src/com/android/bluetooth/hap/HapClientStackEvent.java b/android/app/src/com/android/bluetooth/hap/HapClientStackEvent.java
index 278bb1a06f..e322f505f0 100644
--- a/android/app/src/com/android/bluetooth/hap/HapClientStackEvent.java
+++ b/android/app/src/com/android/bluetooth/hap/HapClientStackEvent.java
@@ -47,20 +47,15 @@ public class HapClientStackEvent {
static final int CONNECTION_STATE_DISCONNECTING = 3;
// Possible operation results
- static final int STATUS_SET_NAME_NOT_ALLOWED =
- IBluetoothHapClient.STATUS_SET_NAME_NOT_ALLOWED;
- static final int STATUS_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_OPERATION_NOT_SUPPORTED;
- static final int STATUS_OPERATION_NOT_POSSIBLE =
- IBluetoothHapClient.STATUS_OPERATION_NOT_POSSIBLE;
- static final int STATUS_INVALID_PRESET_NAME_LENGTH =
- IBluetoothHapClient.STATUS_INVALID_PRESET_NAME_LENGTH;
- static final int STATUS_INVALID_PRESET_INDEX =
- IBluetoothHapClient.STATUS_INVALID_PRESET_INDEX;
- static final int STATUS_GROUP_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_GROUP_OPERATION_NOT_SUPPORTED;
- static final int STATUS_PROCEDURE_ALREADY_IN_PROGRESS =
- IBluetoothHapClient.STATUS_PROCEDURE_ALREADY_IN_PROGRESS;
+ /* WARNING: Matches status codes defined in bta_has.h */
+ static final int STATUS_NO_ERROR = 0;
+ static final int STATUS_SET_NAME_NOT_ALLOWED = 1;
+ static final int STATUS_OPERATION_NOT_SUPPORTED = 2;
+ static final int STATUS_OPERATION_NOT_POSSIBLE = 3;
+ static final int STATUS_INVALID_PRESET_NAME_LENGTH = 4;
+ static final int STATUS_INVALID_PRESET_INDEX = 5;
+ static final int STATUS_GROUP_OPERATION_NOT_SUPPORTED = 6;
+ static final int STATUS_PROCEDURE_ALREADY_IN_PROGRESS = 7;
// Supported features
public static final int FEATURE_BIT_NUM_TYPE_MONAURAL =
@@ -77,16 +72,12 @@ public class HapClientStackEvent {
IBluetoothHapClient.FEATURE_BIT_NUM_WRITABLE_PRESETS;
// Preset Info notification reason
- public static final int PRESET_INFO_REASON_ALL_PRESET_INFO =
- IBluetoothHapClient.PRESET_INFO_REASON_ALL_PRESET_INFO;
- public static final int PRESET_INFO_REASON_PRESET_INFO_UPDATE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_UPDATE;
- public static final int PRESET_INFO_REASON_PRESET_DELETED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_DELETED;
- public static final int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED;
- public static final int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE;
+ /* WARNING: Matches status codes defined in bta_has.h */
+ public static final int PRESET_INFO_REASON_ALL_PRESET_INFO = 0;
+ public static final int PRESET_INFO_REASON_PRESET_INFO_UPDATE = 1;
+ public static final int PRESET_INFO_REASON_PRESET_DELETED = 2;
+ public static final int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED = 3;
+ public static final int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE = 4;
public int type;
public BluetoothDevice device;
@@ -207,6 +198,8 @@ public class HapClientStackEvent {
private String statusCodeValueToString(int value) {
switch (value) {
+ case STATUS_NO_ERROR:
+ return "STATUS_NO_ERROR";
case STATUS_SET_NAME_NOT_ALLOWED:
return "STATUS_SET_NAME_NOT_ALLOWED";
case STATUS_OPERATION_NOT_SUPPORTED:
@@ -222,7 +215,7 @@ public class HapClientStackEvent {
case STATUS_PROCEDURE_ALREADY_IN_PROGRESS:
return "STATUS_PROCEDURE_ALREADY_IN_PROGRESS";
default:
- return "UNKNOWN_STATUS_CODE";
+ return "ERROR_UNKNOWN";
}
}
diff --git a/android/app/src/com/android/bluetooth/hap/HapClientStateMachine.java b/android/app/src/com/android/bluetooth/hap/HapClientStateMachine.java
index 7f10decb19..62c9dd2d14 100644
--- a/android/app/src/com/android/bluetooth/hap/HapClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hap/HapClientStateMachine.java
@@ -238,7 +238,7 @@ final class HapClientStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Disconnected process message(" + mDevice + "): " + messageWhatToString(
+ log("Disconnected: process message(" + mDevice + "): " + messageWhatToString(
message.what));
switch (message.what) {
@@ -343,7 +343,7 @@ final class HapClientStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Connecting process message(" + mDevice + "): "
+ log("Connecting: process message(" + mDevice + "): "
+ messageWhatToString(message.what));
switch (message.what) {
@@ -430,7 +430,7 @@ final class HapClientStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Disconnecting process message(" + mDevice + "): "
+ log("Disconnecting: process message(" + mDevice + "): "
+ messageWhatToString(message.what));
switch (message.what) {
@@ -530,7 +530,7 @@ final class HapClientStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Connected process message(" + mDevice + "): "
+ log("Connected: process message(" + mDevice + "): "
+ messageWhatToString(message.what));
switch (message.what) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientTest.java b/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientTest.java
index 7589ff24ae..6d2f61b240 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hap/HapClientTest.java
@@ -24,8 +24,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Binder;
import android.os.Looper;
import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -39,6 +42,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
+import com.android.bluetooth.le_audio.LeAudioService;
import org.junit.After;
import org.junit.Assert;
@@ -47,13 +51,16 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeoutException;
@@ -69,9 +76,9 @@ public class HapClientTest {
private BluetoothDevice mDevice3;
private Context mTargetContext;
private HapClientService mService;
- private IBluetoothHapClient.Stub mServiceBinder;
private HasIntentReceiver mHasIntentReceiver;
private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mIntentQueue;
+
@Mock
private AdapterService mAdapterService;
@Mock
@@ -82,6 +89,12 @@ public class HapClientTest {
private ServiceFactory mServiceFactory;
@Mock
private CsipSetCoordinatorService mCsipService;
+ @Mock
+ private LeAudioService mLeAudioService;
+ @Mock
+ private IBluetoothHapClientCallback mCallback;
+ @Mock
+ private Binder mBinder;
@Before
public void setUp() throws Exception {
@@ -96,6 +109,8 @@ public class HapClientTest {
Looper.prepare();
}
+ HapClientStateMachine.sConnectTimeoutMs = TIMEOUT_MS;
+
TestUtils.setAdapterService(mAdapterService);
doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
@@ -106,18 +121,15 @@ public class HapClientTest {
mService.mHapClientNativeInterface = mNativeInterface;
mService.mFactory = mServiceFactory;
doReturn(mCsipService).when(mServiceFactory).getCsipSetCoordinatorService();
- mServiceBinder = (IBluetoothHapClient.Stub) mService.initBinder();
- Assert.assertNotNull(mServiceBinder);
+ doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService();
// Set up the State Changed receiver
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHapClient.ACTION_HAP_DEVICE_AVAILABLE);
- filter.addAction(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET);
- filter.addAction(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET_SELECT_ERROR);
- filter.addAction(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO);
- filter.addAction(BluetoothHapClient.ACTION_HAP_ON_PRESET_NAME_SET_ERROR);
- filter.addAction(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO_GET_ERROR);
+
+ when(mCallback.asBinder()).thenReturn(mBinder);
+ mService.mCallbacks.register(mCallback);
mHasIntentReceiver = new HasIntentReceiver();
mTargetContext.registerReceiver(mHasIntentReceiver, filter);
@@ -129,6 +141,27 @@ public class HapClientTest {
mDevice3 = TestUtils.getTestDevice(mAdapter, 2);
when(mNativeInterface.getDevice(getByteAddress(mDevice3))).thenReturn(mDevice3);
+ /* Prepare CAS groups */
+ doReturn(Arrays.asList(0x02, 0x03)).when(mCsipService).getAllGroupIds(BluetoothUuid.CAP);
+
+ int groupId2 = 0x02;
+ Map groups2 = new HashMap<Integer, ParcelUuid>();
+ groups2.put(groupId2, ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"));
+
+ int groupId3 = 0x03;
+ Map groups3 = new HashMap<Integer, ParcelUuid>();
+ groups3.put(groupId3,
+ ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"));
+
+ doReturn(Arrays.asList(mDevice, mDevice2)).when(mLeAudioService).getGroupDevices(groupId2);
+ doReturn(groups2).when(mCsipService).getGroupUuidMapByDevice(mDevice);
+ doReturn(groups2).when(mCsipService).getGroupUuidMapByDevice(mDevice2);
+
+ doReturn(Arrays.asList(mDevice3)).when(mLeAudioService).getGroupDevices(0x03);
+ doReturn(groups3).when(mCsipService).getGroupUuidMapByDevice(mDevice3);
+
+ doReturn(Arrays.asList(mDevice)).when(mLeAudioService).getGroupDevices(0x01);
+
doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService)
.getBondState(any(BluetoothDevice.class));
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
@@ -147,8 +180,12 @@ public class HapClientTest {
R.bool.profile_supported_hap_client)) {
return;
}
+ mService.mCallbacks.unregister(mCallback);
+
stopService();
mTargetContext.unregisterReceiver(mHasIntentReceiver);
+
+ mAdapter = null;
TestUtils.clearAdapterService(mAdapterService);
mIntentQueue.clear();
}
@@ -169,7 +206,7 @@ public class HapClientTest {
* Test getting HA Service Client
*/
@Test
- public void testGetHearingAidService() {
+ public void testGetHapService() {
Assert.assertEquals(mService, HapClientService.getHapClientService());
}
@@ -177,7 +214,7 @@ public class HapClientTest {
* Test stop HA Service Client
*/
@Test
- public void testStopHearingAidService() {
+ public void testStopHapService() {
Assert.assertEquals(mService, HapClientService.getHapClientService());
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@@ -371,14 +408,8 @@ public class HapClientTest {
*/
@Test
public void testCallsForNotConnectedDevice() {
- Assert.assertEquals(true, mService.getActivePresetIndex(mDevice));
-
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(BluetoothHapClient.PRESET_INDEX_UNAVAILABLE,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
+ mService.getActivePresetIndex(mDevice));
}
/**
@@ -395,51 +426,45 @@ public class HapClientTest {
int flags = 0x04;
mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), flags);
- int flags2 = 0x04;
- mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice2), flags);
+ int flags3 = 0x04;
+ mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice3), flags);
/* This one has no coordinated operation support but is part of a coordinated set with
* mDevice, which supports it, thus mDevice will forward the operation to mDevice2.
* This device should also be rocognised as grouped one.
*/
- int flags3 = 0;
- mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice3), flags3);
+ int flags2 = 0;
+ mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice2), flags2);
- /* Prepare CAS groups */
- int base_group_id = 0x03;
- Map groups = new HashMap<Integer, ParcelUuid>();
- groups.put(base_group_id, ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"));
-
- Map groups2 = new HashMap<Integer, ParcelUuid>();
- groups2.put(base_group_id + 1,
- ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB"));
-
- doReturn(groups).when(mCsipService).getGroupUuidMapByDevice(mDevice);
- doReturn(groups).when(mCsipService).getGroupUuidMapByDevice(mDevice3);
- doReturn(groups2).when(mCsipService).getGroupUuidMapByDevice(mDevice2);
-
- /* Two devices support coordinated operations thus shell report valid group ID */
- Assert.assertEquals(base_group_id, mService.getHapGroup(mDevice));
- Assert.assertEquals(base_group_id + 1, mService.getHapGroup(mDevice2));
+ /* Two devices support coordinated operations thus shall report valid group ID */
+ Assert.assertEquals(2, mService.getHapGroup(mDevice));
+ Assert.assertEquals(3, mService.getHapGroup(mDevice3));
/* Third one has no coordinated operations support but is part of the group */
- Assert.assertEquals(base_group_id, mService.getHapGroup(mDevice3));
+ Assert.assertEquals(2, mService.getHapGroup(mDevice2));
}
/**
- * Test that selectActivePreset properly calls the native method.
+ * Test that selectPreset properly calls the native method.
*/
@Test
- public void testSelectActivePresetNative() {
+ public void testSelectPresetNative() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
// Verify Native Interface call
- Assert.assertFalse(mService.selectActivePreset(mDevice, 0x00));
+ mService.selectPreset(mDevice, 0x00);
verify(mNativeInterface, times(0))
.selectActivePreset(eq(mDevice), eq(0x00));
- Assert.assertTrue(mService.selectActivePreset(mDevice, 0x01));
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSelectActivePresetFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ mService.selectPreset(mDevice, 0x01);
verify(mNativeInterface, times(1))
.selectActivePreset(eq(mDevice), eq(0x01));
}
@@ -455,8 +480,15 @@ public class HapClientTest {
mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), flags);
// Verify Native Interface call
- Assert.assertFalse(mService.groupSelectActivePreset(0x03, 0x00));
- Assert.assertTrue(mService.groupSelectActivePreset(0x03, 0x01));
+ mService.selectPresetForGroup(0x03, 0x00);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSelectActivePresetForGroupFailed(
+ eq(0x03), eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ mService.selectPresetForGroup(0x03, 0x01);
verify(mNativeInterface, times(1))
.groupSelectActivePreset(eq(0x03), eq(0x01));
}
@@ -465,13 +497,13 @@ public class HapClientTest {
* Test that nextActivePreset properly calls the native method.
*/
@Test
- public void testNextActivePresetNative() {
+ public void testSwitchToNextPreset() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
// Verify Native Interface call
- Assert.assertTrue(mService.nextActivePreset(mDevice));
+ mService.switchToNextPreset(mDevice);
verify(mNativeInterface, times(1))
.nextActivePreset(eq(mDevice));
}
@@ -480,14 +512,14 @@ public class HapClientTest {
* Test that groupNextActivePreset properly calls the native method.
*/
@Test
- public void testGroupNextActivePresetNative() {
+ public void testSwitchToNextPresetForGroup() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
int flags = 0x01;
mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), flags);
// Verify Native Interface call
- Assert.assertTrue(mService.groupNextActivePreset(0x03));
+ mService.switchToNextPresetForGroup(0x03);
verify(mNativeInterface, times(1)).groupNextActivePreset(eq(0x03));
}
@@ -495,13 +527,13 @@ public class HapClientTest {
* Test that previousActivePreset properly calls the native method.
*/
@Test
- public void testPreviousActivePresetNative() {
+ public void testSwitchToPreviousPreset() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
// Verify Native Interface call
- Assert.assertTrue(mService.previousActivePreset(mDevice));
+ mService.switchToPreviousPreset(mDevice);
verify(mNativeInterface, times(1))
.previousActivePreset(eq(mDevice));
}
@@ -510,7 +542,7 @@ public class HapClientTest {
* Test that groupPreviousActivePreset properly calls the native method.
*/
@Test
- public void testGroupPreviousActivePresetNative() {
+ public void testSwitchToPreviousPresetForGroup() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
@@ -520,7 +552,7 @@ public class HapClientTest {
mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), flags);
// Verify Native Interface call
- Assert.assertTrue(mService.groupPreviousActivePreset(0x03));
+ mService.switchToPreviousPresetForGroup(0x03);
verify(mNativeInterface, times(1)).groupPreviousActivePreset(eq(0x03));
}
@@ -532,39 +564,38 @@ public class HapClientTest {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
- testOnActivePresetSelected(mDevice, 0x01);
+ testOnActivePresetChanged(mDevice, 0x01);
// Verify cached value
- Assert.assertEquals(true, mService.getActivePresetIndex(mDevice));
-
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(0x01,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
+ Assert.assertEquals(0x01, mService.getActivePresetIndex(mDevice));
}
/**
- * Test that getPresetInfo properly calls the native method.
+ * Test that getActivePresetInfo returns cached value for valid parameters.
*/
@Test
- public void testGetPresetInfoNative() {
+ public void testGetActivePresetInfo() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- testConnectingDevice(mDevice);
+ testConnectingDevice(mDevice2);
- // Verify Native Interface call
- Assert.assertFalse(mService.getPresetInfo(mDevice, 0x00));
- verify(mNativeInterface, times(0))
- .getPresetInfo(eq(mDevice), eq(0x00));
- Assert.assertTrue(mService.getPresetInfo(mDevice, 0x01));
- verify(mNativeInterface, times(1))
- .getPresetInfo(eq(mDevice), eq(0x01));
+ // Check when active preset is not known yet
+ Assert.assertEquals(BluetoothHapClient.PRESET_INDEX_UNAVAILABLE,
+ mService.getActivePresetIndex(mDevice2));
+ Assert.assertEquals(null, mService.getActivePresetInfo(mDevice2));
+
+ // Inject active preset change event
+ testOnActivePresetChanged(mDevice2, 0x01);
+
+ // Check when active preset is known
+ Assert.assertEquals(0x01, mService.getActivePresetIndex(mDevice2));
+ BluetoothHapPresetInfo info = mService.getActivePresetInfo(mDevice2);
+ Assert.assertNotNull(info);
+ Assert.assertEquals(0x01, info.getIndex());
}
/**
- * Test that setPresetName properly calls the native method.
+ * Test that setPresetName properly calls the native method for the valid parameters.
*/
@Test
public void testSetPresetNameNative() {
@@ -572,31 +603,57 @@ public class HapClientTest {
.getRemoteUuids(any(BluetoothDevice.class));
testConnectingDevice(mDevice);
- // Verify Native Interface call
- Assert.assertFalse(mService.setPresetName(mDevice, 0x00, "ExamplePresetName"));
+ mService.setPresetName(mDevice, 0x00, "ExamplePresetName");
verify(mNativeInterface, times(0))
.setPresetName(eq(mDevice), eq(0x00), eq("ExamplePresetName"));
- Assert.assertTrue(mService.setPresetName(mDevice, 0x01, "ExamplePresetName"));
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ // Verify Native Interface call
+ mService.setPresetName(mDevice, 0x01, "ExamplePresetName");
verify(mNativeInterface, times(1))
.setPresetName(eq(mDevice), eq(0x01), eq("ExamplePresetName"));
}
/**
- * Test that groupSetPresetName properly calls the native method.
+ * Test that setPresetNameForGroup properly calls the native method for the valid parameters.
*/
@Test
- public void testGroupSetPresetName() {
+ public void testSetPresetNameForGroup() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
+ int test_group = 0x02;
+ for (BluetoothDevice device : mLeAudioService.getGroupDevices(test_group)) {
+ testConnectingDevice(device);
+ }
+
int flags = 0x21;
mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), flags);
+ mService.setPresetNameForGroup(test_group, 0x00, "ExamplePresetName");
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(eq(test_group),
+ eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ mService.setPresetNameForGroup(-1, 0x01, "ExamplePresetName");
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(eq(-1),
+ eq(BluetoothStatusCodes.ERROR_CSIP_INVALID_GROUP_ID));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
// Verify Native Interface call
- Assert.assertFalse(mService.groupSetPresetName(0x03, 0x00, "ExamplePresetName"));
- Assert.assertFalse(mService.groupSetPresetName(-1, 0x01, "ExamplePresetName"));
- Assert.assertTrue(mService.groupSetPresetName(0x03, 0x01, "ExamplePresetName"));
+ mService.setPresetNameForGroup(test_group, 0x01, "ExamplePresetName");
verify(mNativeInterface, times(1))
- .groupSetPresetName(eq(0x03), eq(0x01), eq("ExamplePresetName"));
+ .groupSetPresetName(eq(test_group), eq(0x01), eq("ExamplePresetName"));
}
/**
@@ -607,153 +664,233 @@ public class HapClientTest {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- // Verify getting current preset return an invalid value when there is no such device
- // available
- Assert.assertEquals(true, mService.getActivePresetIndex(mDevice));
-
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(BluetoothHapClient.PRESET_INDEX_UNAVAILABLE,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
-
mNativeInterface.onDeviceAvailable(getByteAddress(mDevice), 0x03);
- intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
+ Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
Assert.assertNotNull(intent);
Assert.assertEquals(BluetoothHapClient.ACTION_HAP_DEVICE_AVAILABLE, intent.getAction());
Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(0x03,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_FEATURES, 0x03));
+ intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_FEATURES, 0x00));
}
/**
- * Test that native callback generates proper intent.
+ * Test that native callback generates proper callback call.
*/
@Test
- public void testStackEventOnActivePresetSelected() {
+ public void testStackEventOnFeaturesUpdate() {
+ doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
+ .getRemoteUuids(any(BluetoothDevice.class));
+
+ mNativeInterface.onDeviceAvailable(getByteAddress(mDevice), 0x00);
+ mNativeInterface.onFeaturesUpdate(getByteAddress(mDevice), 0x03);
+
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onHapFeaturesAvailable(eq(mDevice),
+ eq(0x03));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Test that native callback generates proper callback call.
+ */
+ @Test
+ public void testStackEventOnActivePresetChanged() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
mNativeInterface.onActivePresetSelected(getByteAddress(mDevice), 0x01);
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(0x01,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onActivePresetChanged(eq(mDevice),
+ eq(0x01));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
// Verify that getting current preset returns a proper value now
- Assert.assertEquals(true, mService.getActivePresetIndex(mDevice));
-
- intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(0x01,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
+ Assert.assertEquals(0x01, mService.getActivePresetIndex(mDevice));
}
/**
- * Test that native callback generates proper intent.
+ * Test that native callback generates proper callback call.
*/
@Test
- public void testStackEventOnCurrentPresetSelectError() {
+ public void testStackEventOnActivePresetSelectError() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- mNativeInterface.onActivePresetSelectError(getByteAddress(mDevice),
- BluetoothHapClient.STATUS_INVALID_PRESET_INDEX);
+ /* Send INVALID_PRESET_INDEX error */
+ mNativeInterface.onActivePresetSelectError(getByteAddress(mDevice), 0x05);
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET_SELECT_ERROR,
- intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(BluetoothHapClient.STATUS_INVALID_PRESET_INDEX,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, -1));
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSelectActivePresetFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
- * Test that native callback generates proper intent.
+ * Test that native callback generates proper callback call.
*/
@Test
public void testStackEventOnPresetInfo() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- int info_reason = BluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_UPDATE;
+ // Connect and inject initial presets
+ testConnectingDevice(mDevice);
+
+ int info_reason = HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE;
BluetoothHapPresetInfo[] info =
{new BluetoothHapPresetInfo.Builder()
.setIndex(0x01)
- .setName("PresetName")
+ .setName("OneChangedToUnavailable")
.setWritable(true)
- .setAvailable(true)
+ .setAvailable(false)
.build()};
mNativeInterface.onPresetInfo(getByteAddress(mDevice), info_reason, info);
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO, intent.getAction());
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(info_reason,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO_REASON, -1));
+ ArgumentCaptor<List<BluetoothHapPresetInfo>> presetsCaptor =
+ ArgumentCaptor.forClass(List.class);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onPresetInfoChanged(eq(mDevice),
+ presetsCaptor.capture(), eq(BluetoothStatusCodes.REASON_REMOTE_REQUEST));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
- ArrayList presets =
- intent.getParcelableArrayListExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INFO);
- Assert.assertNotNull(presets);
+ List<BluetoothHapPresetInfo> presets = presetsCaptor.getValue();
+ Assert.assertEquals(3, presets.size());
- BluetoothHapPresetInfo preset = (BluetoothHapPresetInfo) presets.get(0);
- Assert.assertEquals(preset.getIndex(), info[0].getIndex());
- Assert.assertEquals(preset.getName(), info[0].getName());
- Assert.assertEquals(preset.isWritable(), info[0].isWritable());
- Assert.assertEquals(preset.isAvailable(), info[0].isAvailable());
+ Optional<BluetoothHapPresetInfo> preset = presetsCaptor.getValue()
+ .stream()
+ .filter(p -> 0x01 == p.getIndex())
+ .findFirst();
+ Assert.assertEquals("OneChangedToUnavailable", preset.get().getName());
+ Assert.assertFalse(preset.get().isAvailable());
+ Assert.assertTrue(preset.get().isWritable());
}
/**
- * Test that native callback generates proper intent.
+ * Test that native callback generates proper callback call.
*/
@Test
public void testStackEventOnPresetNameSetError() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
+ /* Not a valid name length */
mNativeInterface.onPresetNameSetError(getByteAddress(mDevice), 0x01,
- BluetoothHapClient.STATUS_SET_NAME_NOT_ALLOWED);
+ HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_PRESET_NAME_SET_ERROR,
- intent.getAction());
- Assert.assertEquals(0x01,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(BluetoothHapClient.STATUS_SET_NAME_NOT_ALLOWED,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, -1));
+ /* Invalid preset index provided */
+ mNativeInterface.onPresetNameSetError(getByteAddress(mDevice), 0x01,
+ HapClientStackEvent.STATUS_INVALID_PRESET_INDEX);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on this particular preset */
+ mNativeInterface.onPresetNameSetError(getByteAddress(mDevice), 0x01,
+ HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on this particular preset at this time, might be possible later on */
+ mNativeInterface.onPresetNameSetError(getByteAddress(mDevice), 0x01,
+ HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(2)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on all presets - for example missing characteristic */
+ mNativeInterface.onPresetNameSetError(getByteAddress(mDevice), 0x01,
+ HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameFailed(eq(mDevice),
+ eq(BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
- * Test that native callback generates proper intent.
+ * Test that native callback generates proper callback call.
*/
@Test
- public void testStackEventOnPresetInfoError() {
+ public void testStackEventOnGroupPresetNameSetError() {
doReturn(new ParcelUuid[]{BluetoothUuid.HAS}).when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
- mNativeInterface.onPresetInfoError(getByteAddress(mDevice), 0x01,
- BluetoothHapClient.STATUS_INVALID_PRESET_INDEX);
+ /* Not a valid name length */
+ mNativeInterface.onGroupPresetNameSetError(0x01, 0x01,
+ HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(0x01,
+ BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mDevice));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_PRESET_INFO_GET_ERROR,
- intent.getAction());
- Assert.assertEquals(0x01,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
- Assert.assertEquals(mDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(BluetoothHapClient.STATUS_INVALID_PRESET_INDEX,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_STATUS_CODE, -1));
+ /* Invalid preset index provided */
+ mNativeInterface.onGroupPresetNameSetError(0x01, 0x01,
+ HapClientStackEvent.STATUS_INVALID_PRESET_INDEX);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(0x01,
+ BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on this particular preset */
+ mNativeInterface.onGroupPresetNameSetError(0x01, 0x01,
+ HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(0x01,
+ BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on this particular preset at this time, might be possible later on */
+ mNativeInterface.onGroupPresetNameSetError(0x01, 0x01,
+ HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(2)).onSetPresetNameForGroupFailed(0x01,
+ BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ /* Not allowed on all presets - for example if peer is missing optional CP characteristic */
+ mNativeInterface.onGroupPresetNameSetError(0x01, 0x01,
+ HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED);
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onSetPresetNameForGroupFailed(0x01,
+ BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -812,21 +949,57 @@ public class HapClientTest {
Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
Assert.assertEquals(evt.valueInt1,
intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_FEATURES, -1));
+
+ evt = new HapClientStackEvent(HapClientStackEvent.EVENT_TYPE_DEVICE_FEATURES);
+ evt.device = device;
+ evt.valueInt1 = 0x01; // features
+ mService.messageFromNative(evt);
+
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onHapFeaturesAvailable(eq(device),
+ eq(evt.valueInt1));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ // Inject some initial presets
+ List<BluetoothHapPresetInfo> presets =
+ new ArrayList<BluetoothHapPresetInfo>(Arrays.asList(
+ new BluetoothHapPresetInfo.Builder()
+ .setIndex(0x01)
+ .setName("One")
+ .setAvailable(true)
+ .setWritable(false)
+ .build(),
+ new BluetoothHapPresetInfo.Builder()
+ .setIndex(0x02)
+ .setName("Two")
+ .setAvailable(true)
+ .setWritable(true)
+ .build(),
+ new BluetoothHapPresetInfo.Builder()
+ .setIndex(0x03)
+ .setName("Three")
+ .setAvailable(false)
+ .setWritable(false)
+ .build()));
+ mService.updateDevicePresetsCache(device,
+ HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO, presets);
}
- private void testOnActivePresetSelected(BluetoothDevice device, int index) {
+ private void testOnActivePresetChanged(BluetoothDevice device, int index) {
HapClientStackEvent evt =
new HapClientStackEvent(HapClientStackEvent.EVENT_TYPE_ON_ACTIVE_PRESET_SELECTED);
evt.device = device;
evt.valueInt1 = index;
mService.messageFromNative(evt);
- Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(device));
- Assert.assertNotNull(intent);
- Assert.assertEquals(BluetoothHapClient.ACTION_HAP_ON_ACTIVE_PRESET, intent.getAction());
- Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
- Assert.assertEquals(index,
- intent.getIntExtra(BluetoothHapClient.EXTRA_HAP_PRESET_INDEX, -1));
+ try {
+ verify(mCallback, after(TIMEOUT_MS).times(1)).onActivePresetChanged(eq(device),
+ eq(evt.valueInt1));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/floss/OWNERS b/floss/OWNERS
new file mode 100644
index 0000000000..45bfdd2be4
--- /dev/null
+++ b/floss/OWNERS
@@ -0,0 +1 @@
+include platform/packages/modules/Bluetooth:/OWNERS_chromeos
diff --git a/floss/build/Dockerfile b/floss/build/Dockerfile
new file mode 100644
index 0000000000..7e938f9a10
--- /dev/null
+++ b/floss/build/Dockerfile
@@ -0,0 +1,76 @@
+# Build environment for Floss
+#
+# This dockerfile generates the build environment required to build Floss, which
+# is the Linux build for the Fluoride Bluetooth stack.
+
+# Inherit from a recent Debian version. The slim version is a smaller variant
+# meant for containers.
+FROM debian:bookworm-slim
+
+# First install all required apt packages.
+RUN apt-get update && \
+ apt-get install -y \
+ bison \
+ build-essential \
+ clang \
+ cmake \
+ curl \
+ debmake \
+ flatbuffers-compiler \
+ flex \
+ g++-multilib \
+ gcc-multilib \
+ generate-ninja \
+ gnupg \
+ gperf \
+ libabsl-dev \
+ libc++abi-dev \
+ libc++-dev \
+ libdbus-1-dev \
+ libdouble-conversion-dev \
+ libevent-dev \
+ libflatbuffers-dev \
+ libflatbuffers1 \
+ libgl1-mesa-dev \
+ libglib2.0-dev \
+ libgtest-dev \
+ libgmock-dev \
+ liblz4-tool \
+ libncurses5 \
+ libnss3-dev \
+ libprotobuf-dev \
+ libre2-9 \
+ libre2-dev \
+ libssl-dev \
+ libtinyxml2-dev \
+ libx11-dev \
+ libxml2-utils \
+ ninja-build \
+ openssl \
+ protobuf-compiler \
+ python3 \
+ unzip \
+ x11proto-core-dev \
+ xsltproc \
+ zip \
+ zlib1g-dev \
+ ;
+
+# Next install the Rust toolchain.
+RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+
+# Add .cargo/bin to $PATH
+ENV PATH="/root/.cargo/bin:${PATH}"
+
+# Install cargo packages required on build image.
+RUN cargo install cxxbridge-cmd --version 1.0.42
+
+# Rename llvm packages. By default, they are named 11vm-ar-13, etc. which won't
+# work properly with the build.
+ADD llvm-rename.sh /tmp
+RUN /tmp/llvm-rename.sh 13
+
+# At this point, the base container is ready. Now we need to build and install
+# both libchrome and modp-b64. If you ran this via `docker-build-image.py`, this
+# will be done after the image is created and tagged. Otherwise, you need to
+# manually mount the source and run the dpkg builders in `system/build/dpkg`.
diff --git a/floss/build/README.md b/floss/build/README.md
new file mode 100644
index 0000000000..ac58410fb1
--- /dev/null
+++ b/floss/build/README.md
@@ -0,0 +1,23 @@
+# Docker build for Floss
+
+This repo contains the Docker image build rule, used to generate the docker
+image necessary to build Floss. If building a new docker image, run
+`docker-build-image.py` with the tag `floss:latest`.
+
+## Using the docker image to build
+
+Once the Docker image is built (and assuming it's tagged as `floss:latest`), you
+should use the `build-in-docker.py` script to build the current repo.
+
+This script will use the local `floss:latest` (or pull it from the registry),
+mount (or create) the `floss-out` volume to `/root/.floss` and the current
+source to `/root/src` before running these commands in the container:
+
+* `cd /root/src`
+* `./build.py --run-bootstrap`
+* `./build.py --libdir=/usr/lib/x86-64_linux_gnu/`
+
+If you want to run the build more quickly (or pass other commands), run
+`build-in-docker.py --only-start`. This will only start the container for you
+(doing the correct mounts) and will print the commands it would have run via
+docker exec normally.
diff --git a/floss/build/build-in-docker.py b/floss/build/build-in-docker.py
new file mode 100755
index 0000000000..a84d2dd7c9
--- /dev/null
+++ b/floss/build/build-in-docker.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+class FlossDockerRunner:
+ """Runs Floss build inside docker container."""
+
+ # Commands to run for build
+ BUILD_COMMANDS = [
+ # First run bootstrap to get latest code + create symlinks
+ ['/root/src/build.py', '--run-bootstrap'],
+
+ # Clean up any previous artifacts inside the volume
+ ['/root/src/build.py', '--target', 'clean'],
+
+ # Run normal code builder
+ ['/root/src/build.py', '--target', 'all'],
+
+ # Run tests
+ ['/root/src/build.py', '--target', 'test'],
+ ]
+
+ def __init__(self, workdir, rootdir, image_tag, volume_tag):
+ """ Constructor.
+
+ Args:
+ workdir: Current working directory (should be the script path).
+ rootdir: Root directory for Bluetooth.
+ build_tag: Tag for docker image used for building.
+ """
+ self.workdir = workdir
+ self.rootdir = rootdir
+ self.image_tag = image_tag
+ self.env = os.environ.copy()
+
+ # Name of running container
+ self.container_name = 'floss-docker-runner'
+
+ # Name of volume where we'll send build output
+ self.volume_name = volume_tag
+
+ def run_command(self, target, args, cwd=None, env=None, ignore_rc=False):
+ """ Run command and stream the output.
+ """
+ # Set some defaults
+ if not cwd:
+ cwd = self.workdir
+ if not env:
+ env = self.env
+
+ rc = 0
+ process = subprocess.Popen(args, cwd=cwd, env=env, stdout=subprocess.PIPE)
+ while True:
+ line = process.stdout.readline()
+ print(line.decode('utf-8'), end="")
+ if not line:
+ rc = process.poll()
+ if rc is not None:
+ break
+
+ time.sleep(0.1)
+
+ if rc != 0 and not ignore_rc:
+ raise Exception("{} failed. Return code is {}".format(target, rc))
+
+ def _create_volume_if_needed(self):
+ # Check if the volume exists. Otherwise create it.
+ try:
+ subprocess.check_output(['docker', 'volume', 'inspect', self.volume_name])
+ finally:
+ self.run_command('docker volume create', ['docker', 'volume', 'create', self.volume_name])
+
+ def start_container(self):
+ """Starts the docker container with correct mounts."""
+ # Stop any previously started container.
+ self.stop_container(ignore_error=True)
+
+ # Create volume and create mount string
+ self._create_volume_if_needed()
+ mount_output_volume = 'type=volume,src={},dst=/root/.floss'.format(self.volume_name)
+
+ # Mount the source directory
+ mount_src_dir = 'type=bind,src={},dst=/root/src'.format(self.rootdir)
+
+ # Run the docker image. It will run `tail` indefinitely so the container
+ # doesn't close and we can run `docker exec` on it.
+ self.run_command('docker run', [
+ 'docker', 'run', '--name', self.container_name, '--mount', mount_output_volume, '--mount', mount_src_dir,
+ '-d', self.image_tag, 'tail', '-f', '/dev/null'
+ ])
+
+ def stop_container(self, ignore_error=False):
+ """Stops the docker container for build."""
+ self.run_command('docker stop', ['docker', 'stop', '-t', '1', self.container_name], ignore_rc=ignore_error)
+ self.run_command('docker rm', ['docker', 'rm', self.container_name], ignore_rc=ignore_error)
+
+ def do_build(self):
+ """Runs the basic build commands."""
+ # Start container before building
+ self.start_container()
+
+ # Run all commands
+ for i, cmd in enumerate(self.BUILD_COMMANDS):
+ self.run_command('docker exec #{}'.format(i), ['docker', 'exec', '-it', self.container_name] + cmd)
+
+ # Stop container before exiting
+ self.stop_container()
+
+ def print_do_build(self):
+ """Prints the commands for building."""
+ docker_exec = ['docker', 'exec', '-it', self.container_name]
+ print('Normally, build would run the following commands: \n')
+ for cmd in self.BUILD_COMMANDS:
+ print(' '.join(docker_exec + cmd))
+
+ def check_docker_runnable(self):
+ try:
+ subprocess.check_output(['docker', 'ps'], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as err:
+ if 'denied' in err.output.decode('utf-8'):
+ print('Run script as sudo')
+ else:
+ print('Unexpected error: {}'.format(err.output.decode('utf-8')))
+
+ return False
+
+ # No exception means docker is ok
+ return True
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser('Builder Floss inside docker image.')
+ parser.add_argument(
+ '--only-start',
+ action='store_true',
+ default=False,
+ help='Only start the container. Prints the commands it would have ran.')
+ parser.add_argument('--only-stop', action='store_true', default=False, help='Only stop the container and exit.')
+ parser.add_argument('--image-tag', default='floss:latest', help='Docker image to use to build.')
+ parser.add_argument('--volume-tag', default='floss-out', help='Name of volume to use.')
+ args = parser.parse_args()
+
+ # cwd should be set to same directory as this script (that's where Dockerfile
+ # is kept).
+ workdir = os.path.dirname(os.path.abspath(sys.argv[0]))
+ rootdir = os.path.abspath(os.path.join(workdir, '../..'))
+
+ fdr = FlossDockerRunner(workdir, rootdir, args.image_tag, args.volume_tag)
+
+ # Make sure docker is runnable before continuing
+ if fdr.check_docker_runnable():
+ # Handle some flags
+ if args.only_start:
+ fdr.start_container()
+ fdr.print_do_build()
+ elif args.only_stop:
+ fdr.stop_container()
+ else:
+ fdr.do_build()
diff --git a/floss/build/docker-build-image.py b/floss/build/docker-build-image.py
new file mode 100755
index 0000000000..81b622b87b
--- /dev/null
+++ b/floss/build/docker-build-image.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import sys
+import subprocess
+
+SRC_MOUNT = "/root/src"
+
+
+class DockerImageBuilder:
+ """Builds the docker image for Floss build environment."""
+
+ def __init__(self, workdir, rootdir, tag):
+ """ Constructor.
+
+ Args:
+ workdir: Working directory for this script. Dockerfile should exist here.
+ rootdir: Root directory for Bluetooth.
+ tag: Label in format |name:version|.
+ """
+ self.workdir = workdir
+ self.rootdir = rootdir
+ (self.name, self.version) = tag.split(':')
+ self.build_tag = '{}:{}'.format(self.name, 'buildtemp')
+ self.container_name = 'floss-buildtemp'
+ self.final_tag = tag
+ self.env = os.environ.copy()
+
+ # Mark dpkg builders for docker
+ self.env['LIBCHROME_DOCKER'] = '1'
+ self.env['MODP_DOCKER'] = '1'
+
+ def run_command(self, target, args, cwd=None, env=None, ignore_rc=False):
+ """ Run command and stream the output.
+ """
+ # Set some defaults
+ if not cwd:
+ cwd = self.workdir
+ if not env:
+ env = self.env
+
+ rc = 0
+ process = subprocess.Popen(args, cwd=cwd, env=env, stdout=subprocess.PIPE)
+ while True:
+ line = process.stdout.readline()
+ print(line.decode('utf-8'), end="")
+ if not line:
+ rc = process.poll()
+ if rc is not None:
+ break
+
+ time.sleep(0.1)
+
+ if rc != 0 and not ignore_rc:
+ raise Exception("{} failed. Return code is {}".format(target, rc))
+
+ def _docker_build(self):
+ self.run_command('docker build', ['docker', 'build', '-t', self.build_tag, '.'])
+
+ def _build_dpkg_and_commit(self):
+ # Try to remove any previous instance of the container that may be
+ # running if this script didn't complete cleanly last time.
+ self.run_command('docker stop', ['docker', 'stop', '-t', '1', self.container_name], ignore_rc=True)
+ self.run_command('docker rm', ['docker', 'rm', self.container_name], ignore_rc=True)
+
+ # Runs never terminating application on the newly built image in detached mode
+ mount_str = 'type=bind,src={},dst={},readonly'.format(self.rootdir, SRC_MOUNT)
+ self.run_command('docker run', [
+ 'docker', 'run', '--name', self.container_name, '--mount', mount_str, '-d', self.build_tag, 'tail', '-f',
+ '/dev/null'
+ ])
+
+ commands = [
+ # Create the output directories
+ ['mkdir', '-p', '/tmp/libchrome', '/tmp/modpb64'],
+
+ # Run the dpkg builder for modp_b64
+ ['/root/src/system/build/dpkg/modp_b64/gen-src-pkg.sh', '/tmp/modpb64'],
+
+ # Install modp_b64 since libchrome depends on it
+ ['find', '/tmp/modpb64', '-name', 'modp*.deb', '-exec', 'dpkg', '-i', '{}', '+'],
+
+ # Run the dpkg builder for libchrome
+ ['/root/src/system/build/dpkg/libchrome/gen-src-pkg.sh', '/tmp/libchrome'],
+
+ # Install libchrome.
+ ['find', '/tmp/libchrome', '-name', 'libchrome_*.deb', '-exec', 'dpkg', '-i', '{}', '+'],
+
+ # Delete intermediate files
+ ['rm', '-rf', '/tmp/libchrome', '/tmp/modpb64'],
+ ]
+
+ # Run commands in container first to install everything.
+ for i, cmd in enumerate(commands):
+ self.run_command('docker exec #{}'.format(i), ['docker', 'exec', '-it', self.container_name] + cmd)
+
+ # Commit changes into the final tag name
+ self.run_command('docker commit', ['docker', 'commit', self.container_name, self.final_tag])
+
+ # Stop running the container and remove it
+ self.run_command('docker stop', ['docker', 'stop', '-t', '1', self.container_name])
+ self.run_command('docker rm', ['docker', 'rm', self.container_name])
+
+ def _check_docker_runnable(self):
+ try:
+ subprocess.check_output(['docker', 'ps'], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as err:
+ if 'denied' in err.output.decode('utf-8'):
+ print('Run script as sudo')
+ else:
+ print('Unexpected error: {}'.format(err.output.decode('utf-8')))
+
+ return False
+
+ # No exception means docker is ok
+ return True
+
+ def build(self):
+ if not self._check_docker_runnable():
+ return
+
+ # First build the docker image
+ self._docker_build()
+
+ # Then build libchrome and modp-b64 inside the docker image and install
+ # them. Commit those changes to the final label.
+ self._build_dpkg_and_commit()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Build docker image for Floss build environment.')
+ parser.add_argument('--tag', required=True, help='Tag for docker image. i.e. floss:latest')
+ args = parser.parse_args()
+
+ # cwd should be set to same directory as this script (that's where Dockerfile
+ # is kept).
+ workdir = os.path.dirname(os.path.abspath(sys.argv[0]))
+ rootdir = os.path.abspath(os.path.join(workdir, '../..'))
+
+ # Build the docker image
+ dib = DockerImageBuilder(workdir, rootdir, args.tag)
+ dib.build()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/floss/build/llvm-rename.sh b/floss/build/llvm-rename.sh
new file mode 100755
index 0000000000..454d19bf99
--- /dev/null
+++ b/floss/build/llvm-rename.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+# Rename all llvm binaries using update-alternatives
+# Without this, the llvm binaries must have the version appended at the end
+# instead of just using the base name
+function rename_llvm_binaries {
+ version=$1
+ priority=100
+
+ update-alternatives \
+ --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-${version} ${priority} \
+ --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-${version} \
+ --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-${version} \
+ --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-${version} \
+ --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-${version} \
+ --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-${version} \
+ --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-${version} \
+ --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-${version} \
+ --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-${version} \
+ --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-${version} \
+ --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-${version} \
+ --slave /usr/bin/llvm-mcmarkup llvm-mcmarkup /usr/bin/llvm-mcmarkup-${version} \
+ --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-${version} \
+ --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-${version} \
+ --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-${version} \
+ --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-${version} \
+ --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-${version} \
+ --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-${version} \
+ --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-${version} \
+ --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-${version} \
+ --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-${version}
+
+ update-alternatives \
+ --install /usr/bin/clang clang /usr/bin/clang-${version} ${priority} \
+ --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${version} \
+ --slave /usr/bin/asan_symbolize asan_symbolize /usr/bin/asan_symbolize-${version} \
+ --slave /usr/bin/c-index-test c-index-test /usr/bin/c-index-test-${version} \
+ --slave /usr/bin/clang-check clang-check /usr/bin/clang-check-${version} \
+ --slave /usr/bin/clang-cl clang-cl /usr/bin/clang-cl-${version} \
+ --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-${version} \
+ --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-${version} \
+ --slave /usr/bin/clang-format-diff clang-format-diff /usr/bin/clang-format-diff-${version} \
+ --slave /usr/bin/clang-import-test clang-import-test /usr/bin/clang-import-test-${version} \
+ --slave /usr/bin/clang-include-fixer clang-include-fixer /usr/bin/clang-include-fixer-${version} \
+ --slave /usr/bin/clang-offload-bundler clang-offload-bundler /usr/bin/clang-offload-bundler-${version} \
+ --slave /usr/bin/clang-query clang-query /usr/bin/clang-query-${version} \
+ --slave /usr/bin/clang-rename clang-rename /usr/bin/clang-rename-${version} \
+ --slave /usr/bin/clang-reorder-fields clang-reorder-fields /usr/bin/clang-reorder-fields-${version} \
+ --slave /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-${version} \
+ --slave /usr/bin/lldb lldb /usr/bin/lldb-${version} \
+ --slave /usr/bin/lldb-server lldb-server /usr/bin/lldb-server-${version}
+
+ # Use clang instead of cc by default
+ update-alternatives --install /usr/bin/cc cc /usr/bin/clang $priority
+}
+
+rename_llvm_binaries $@
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 4042e66057..a47cc0a506 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -697,6 +697,7 @@ package android.bluetooth {
field @NonNull public static final android.os.ParcelUuid AVRCP_CONTROLLER;
field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
field @NonNull public static final android.os.ParcelUuid BASE_UUID;
+ field @NonNull public static final android.os.ParcelUuid BASS;
field @NonNull public static final android.os.ParcelUuid BNEP;
field @NonNull public static final android.os.ParcelUuid CAP;
field @NonNull public static final android.os.ParcelUuid COORDINATED_SET;
diff --git a/framework/java/android/bluetooth/BluetoothHapClient.java b/framework/java/android/bluetooth/BluetoothHapClient.java
index 2b245bcb41..fd769d412b 100644
--- a/framework/java/android/bluetooth/BluetoothHapClient.java
+++ b/framework/java/android/bluetooth/BluetoothHapClient.java
@@ -25,6 +25,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.content.AttributionSource;
@@ -39,7 +40,9 @@ import com.android.modules.utils.SynchronousResultReceiver;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
@@ -58,6 +61,8 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
private static final boolean DBG = false;
private static final boolean VDBG = false;
+ private final Map<Callback, Executor> mCallbackExecutorMap = new HashMap<>();
+
private CloseGuard mCloseGuard;
/**
@@ -83,17 +88,6 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
@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.
*
@@ -180,6 +174,87 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
void onSetPresetNameForGroupFailed(int hapGroupId, @Status int status);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
+ private final IBluetoothHapClientCallback mCallback = new IBluetoothHapClientCallback.Stub() {
+ @Override
+ public void onActivePresetChanged(@NonNull BluetoothDevice device, int presetIndex) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onActivePresetChanged(device, presetIndex));
+ }
+ }
+
+ @Override
+ public void onSelectActivePresetFailed(@NonNull BluetoothDevice device, int status) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSelectActivePresetFailed(device, status));
+ }
+ }
+
+ @Override
+ public void onSelectActivePresetForGroupFailed(int hapGroupId, int statusCode) {
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(
+ () -> callback.onSelectActivePresetForGroupFailed(hapGroupId, statusCode));
+ }
+ }
+
+ @Override
+ public void onPresetInfoChanged(@NonNull BluetoothDevice device,
+ @NonNull List<BluetoothHapPresetInfo> presetInfoList, int statusCode) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(
+ () -> callback.onPresetInfoChanged(device, presetInfoList, statusCode));
+ }
+ }
+
+ @Override
+ public void onHapFeaturesAvailable(@NonNull BluetoothDevice device, int hapFeatures) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onHapFeaturesAvailable(device, hapFeatures));
+ }
+ }
+
+ @Override
+ public void onSetPresetNameFailed(@NonNull BluetoothDevice device, int status) {
+ Attributable.setAttributionSource(device, mAttributionSource);
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSetPresetNameFailed(device, status));
+ }
+ }
+
+ @Override
+ public void onSetPresetNameForGroupFailed(int hapGroupId, int status) {
+ for (Map.Entry<BluetoothHapClient.Callback, Executor> callbackExecutorEntry:
+ mCallbackExecutorMap.entrySet()) {
+ BluetoothHapClient.Callback callback = callbackExecutorEntry.getKey();
+ Executor executor = callbackExecutorEntry.getValue();
+ executor.execute(() -> callback.onSetPresetNameForGroupFailed(hapGroupId, 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
@@ -229,235 +304,12 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
"android.bluetooth.action.HAP_DEVICE_AVAILABLE";
/**
- * Intent used to broadcast HA device's feature set.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_FEATURES}- 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}.</li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_DEVICE_FEATURES =
- "android.bluetooth.action.HAP_ON_DEVICE_FEATURES";
-
- /**
- * Intent used to broadcast the change of a HA device's active preset.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_ACTIVE_PRESET =
- "android.bluetooth.action.HAP_ON_ACTIVE_PRESET";
-
- /**
- * Intent used to broadcast the result of a failed preset change attempt.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_INVALID_PRESET_INDEX},
- * {@link #STATUS_OPERATION_NOT_POSSIBLE},{@link #STATUS_OPERATION_NOT_SUPPORTED}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_ACTIVE_PRESET_SELECT_ERROR =
- "android.bluetooth.action.HAP_ON_ACTIVE_PRESET_SELECT_ERROR";
-
- /**
- * Intent used to broadcast preset name change.
- *
- * <p>This intent will have 4 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INFO}- List of preset informations </li>
- * <li> {@link #EXTRA_HAP_PRESET_INFO_REASON}- Why this preset info notification was sent </li>
- * notifications or the user should expect more to come. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_INFO =
- "android.bluetooth.action.HAP_ON_PRESET_INFO";
-
- /**
- * Intent used to broadcast result of a failed rename attempt.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason code.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_SET_NAME_NOT_ALLOWED},
- * {@link #STATUS_INVALID_PRESET_INDEX}, {@link #STATUS_INVALID_PRESET_NAME_LENGTH}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_NAME_SET_ERROR =
- "android.bluetooth.action.HAP_ON_PRESET_NAME_SET_ERROR";
-
- /**
- * Intent used to broadcast the result of a failed name get attempt.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_HAP_PRESET_INDEX}- The currently active preset.</li>
- * <li> {@link #EXTRA_HAP_STATUS_CODE}- Failure reason code.</li>
- * </ul>
- *
- * <p>{@link #EXTRA_HAP_STATUS_CODE} can be any of {@link #STATUS_INVALID_PRESET_INDEX},
- * {@link #STATUS_OPERATION_NOT_POSSIBLE}.
- *
- * @hide
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HAP_ON_PRESET_INFO_GET_ERROR =
- "android.bluetooth.action.HAP_ON_PRESET_INFO_GET_ERROR";
-
- /**
* Contains a list of all available presets
* @hide
*/
public static final String EXTRA_HAP_FEATURES = "android.bluetooth.extra.HAP_FEATURES";
/**
- * Contains a preset identifier
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INDEX = "android.bluetooth.extra.HAP_PRESET_INDEX";
-
- /**
- * Used to report failure reasons.
- * @hide
- */
- public static final String EXTRA_HAP_STATUS_CODE = "android.bluetooth.extra.HAP_STATUS_CODE";
-
- /**
- * Used by group events.
- * @hide
- */
- public static final String EXTRA_HAP_GROUP_ID = "android.bluetooth.extra.HAP_GROUP_ID";
-
- /**
- * Preset Info reason.
- * Possible values:
- * {@link #PRESET_INFO_REASON_ALL_PRESET_INFO} or
- * {@link #PRESET_INFO_REASON_PRESET_INFO_UPDATE} or
- * {@link #PRESET_INFO_REASON_PRESET_DELETED} or
- * {@link #PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED} or
- * {@link #PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE}
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INFO_REASON =
- "android.bluetooth.extra.HAP_PRESET_INFO_REASON";
-
- /**
- * Preset Info.
- * @hide
- */
- public static final String EXTRA_HAP_PRESET_INFO = "android.bluetooth.extra.HAP_PRESET_INFO";
-
- /**
- * Preset name change failure due to preset being read-only.
- * @hide
- */
- public static final int STATUS_SET_NAME_NOT_ALLOWED =
- IBluetoothHapClient.STATUS_SET_NAME_NOT_ALLOWED;
-
- /**
- * Means that the requested operation is not supported by the HA device.
- *
- * <p> It could mean that the requested name change is not supported on
- * a given preset or the device does not support presets at all.
- * @hide
- */
- public static final int STATUS_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_OPERATION_NOT_SUPPORTED;
-
- /**
- * Usually means a temporary denial of certain operation. Peer device may report this
- * status due to various implementation specific reasons. It's different than
- * the {@link #STATUS_OPERATION_NOT_SUPPORTED} which represents more of a
- * permanent inability to perform some of the operations.
- * @hide
- */
- public static final int STATUS_OPERATION_NOT_POSSIBLE =
- IBluetoothHapClient.STATUS_OPERATION_NOT_POSSIBLE;
-
- /**
- * Used when preset name change failed due to the passed name parameter being to long.
- * @hide
- */
- public static final int STATUS_INVALID_PRESET_NAME_LENGTH =
- IBluetoothHapClient.STATUS_INVALID_PRESET_NAME_LENGTH;
-
- /**
- * Group operations are not supported.
- * @hide
- */
- public static final int STATUS_GROUP_OPERATION_NOT_SUPPORTED =
- IBluetoothHapClient.STATUS_GROUP_OPERATION_NOT_SUPPORTED;
-
- /**
- * Procedure is already in progress.
- * @hide
- */
- public static final int STATUS_PROCEDURE_ALREADY_IN_PROGRESS =
- IBluetoothHapClient.STATUS_PROCEDURE_ALREADY_IN_PROGRESS;
-
- /**
- * Invalid preset index input parameter used in one of the API calls.
- * @hide
- */
- public static final int STATUS_INVALID_PRESET_INDEX =
- IBluetoothHapClient.STATUS_INVALID_PRESET_INDEX;
-
- /**
* Represets an invalid index value. This is usually value returned in a currently
* active preset request for a device which is not connected. This value shouldn't be used
* in the API calls.
@@ -507,48 +359,6 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
public static final int FEATURE_BIT_NUM_WRITABLE_PRESETS =
IBluetoothHapClient.FEATURE_BIT_NUM_WRITABLE_PRESETS;
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_ALL_PRESET_INFO =
- IBluetoothHapClient.PRESET_INFO_REASON_ALL_PRESET_INFO;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_INFO_UPDATE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_UPDATE;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_DELETED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_DELETED;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED;
-
- /**
- * Preset Info notification reason.
- * @hide
- */
- public static final int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE =
- IBluetoothHapClient.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE;
-
- /**
- * Represents invalid group identifier. It's returned when user requests a group identifier
- * for a device which is not part of any group. This value shouldn't be used in the API calls.
- * @hide
- */
- public static final int HAP_GROUP_UNAVAILABLE = IBluetoothHapClient.GROUP_ID_UNAVAILABLE;
-
private final BluetoothAdapter mAdapter;
private final AttributionSource mAttributionSource;
private final BluetoothProfileConnector<IBluetoothHapClient> mProfileConnector =
@@ -560,6 +370,35 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
}
};
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (up) {
+ // re-register the service-to-app callback
+ synchronized (mCallbackExecutorMap) {
+ if (mCallbackExecutorMap.isEmpty()) return;
+
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv =
+ new SynchronousResultReceiver();
+ service.registerCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n"
+ + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+ };
+
/**
* Create a BluetoothHapClient proxy object for interacting with the local
* Bluetooth Hearing Access Profile (HAP) client.
@@ -568,6 +407,16 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
mAdapter = BluetoothAdapter.getDefaultAdapter();
mAttributionSource = mAdapter.getAttributionSource();
mProfileConnector.connect(context, listener);
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
mCloseGuard = new CloseGuard();
mCloseGuard.open("close");
}
@@ -586,6 +435,17 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
* @hide
*/
public void close() {
+ if (VDBG) log("close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
mProfileConnector.disconnect();
}
@@ -621,8 +481,36 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
+ if (!isEnabled()) {
+ throw new IllegalStateException("service not enabled");
+ }
+
if (DBG) log("registerCallback");
- throw new UnsupportedOperationException("Not Implemented");
+
+ synchronized (mCallbackExecutorMap) {
+ // If the callback map is empty, we register the service-to-app callback
+ if (mCallbackExecutorMap.isEmpty()) {
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv =
+ new SynchronousResultReceiver();
+ service.registerCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (IllegalStateException | TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ // Adds the passed in callback to our map of callbacks to executors
+ if (mCallbackExecutorMap.containsKey(callback)) {
+ throw new IllegalArgumentException("This callback has already been registered");
+ }
+ mCallbackExecutorMap.put(callback, executor);
+ }
}
/**
@@ -646,8 +534,30 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
+
if (DBG) log("unregisterCallback");
- throw new UnsupportedOperationException("Not Implemented");
+
+ synchronized (mCallbackExecutorMap) {
+ if (mCallbackExecutorMap.remove(callback) != null) {
+ throw new IllegalArgumentException("This callback has not been registered");
+ }
+ }
+
+ // If the callback map is empty, we unregister the service-to-app callback
+ if (mCallbackExecutorMap.isEmpty()) {
+ try {
+ final IBluetoothHapClient service = getService();
+ if (service != null) {
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
+ service.unregisterCallback(mCallback, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
+ }
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
/**
@@ -683,8 +593,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -719,8 +631,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getConnectionPolicy(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -748,9 +662,13 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
try {
final SynchronousResultReceiver<List> recv = new SynchronousResultReceiver();
service.getConnectedDevices(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ return Attributable.setAttributionSource(
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
+ mAttributionSource);
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -779,9 +697,13 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
try {
final SynchronousResultReceiver<List> recv = new SynchronousResultReceiver();
service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ return Attributable.setAttributionSource(
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
+ mAttributionSource);
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -811,8 +733,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getConnectionState(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -828,12 +752,11 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
* require individual device calls.
*
* <p>Note that some binaural HA devices may not support group operations,
- * therefore are not considered a valid HAP group. In such case the
- * {@link #HAP_GROUP_UNAVAILABLE} is returned even when such
- * device is a valid Le Audio Coordinated Set member.
+ * therefore are not considered a valid HAP group. In such case -1 is returned
+ * even if such device is a valid Le Audio Coordinated Set member.
*
* @param device
- * @return valid group identifier or {@link #HAP_GROUP_UNAVAILABLE}
+ * @return valid group identifier or -1
* @hide
*/
@RequiresBluetoothConnectPermission
@@ -843,7 +766,7 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public int getHapGroup(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final int defaultValue = HAP_GROUP_UNAVAILABLE;
+ final int defaultValue = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
@@ -852,8 +775,10 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getHapGroup(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -878,14 +803,15 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // 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()));
- // }
+ try {
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
+ service.getActivePresetIndex(device, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
return defaultValue;
}
@@ -905,8 +831,25 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
public @Nullable BluetoothHapPresetInfo getActivePresetInfo(@NonNull BluetoothDevice device) {
- // TODO(b/216639668)
- return null;
+ final IBluetoothHapClient service = getService();
+ final BluetoothHapPresetInfo defaultValue = null;
+ 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<BluetoothHapPresetInfo> recv =
+ new SynchronousResultReceiver();
+ service.getActivePresetInfo(device, mAttributionSource, recv);
+ recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ return defaultValue;
}
/**
@@ -928,18 +871,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void selectPreset(@NonNull BluetoothDevice device, int presetIndex) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.selectPreset(device, presetIndex, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -968,18 +907,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void selectPresetForGroup(int groupId, int presetIndex) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.selectPresetForGroup(groupId, presetIndex, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1000,18 +935,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToNextPreset(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToNextPreset(device, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1034,18 +965,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToNextPresetForGroup(int groupId) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToNextPresetForGroup(groupId, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1066,18 +993,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToPreviousPreset(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToPreviousPreset(device, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1100,18 +1023,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void switchToPreviousPresetForGroup(int groupId) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.switchToPreviousPresetForGroup(groupId, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1129,24 +1048,26 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
- public @NonNull BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device,
+ public @Nullable BluetoothHapPresetInfo getPresetInfo(@NonNull BluetoothDevice device,
int presetIndex) {
final IBluetoothHapClient service = getService();
- final BluetoothHapPresetInfo.Builder builder = new BluetoothHapPresetInfo.Builder();
+ final BluetoothHapPresetInfo defaultValue = null;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // 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()));
- // }
+ try {
+ final SynchronousResultReceiver<BluetoothHapPresetInfo> recv =
+ new SynchronousResultReceiver();
+ service.getPresetInfo(device, presetIndex, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
- return builder.build();
+ return defaultValue;
}
/**
@@ -1169,14 +1090,16 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled() && isValidDevice(device)) {
- // 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()));
- // }
+ try {
+ final SynchronousResultReceiver<List<BluetoothHapPresetInfo>> recv =
+ new SynchronousResultReceiver();
+ service.getAllPresetInfo(device, mAttributionSource, recv);
+ return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
+ } catch (TimeoutException e) {
+ Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
return defaultValue;
}
@@ -1193,19 +1116,21 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED
})
- public boolean getFeatures(@NonNull BluetoothDevice device) {
+ public int getFeatures(@NonNull BluetoothDevice device) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
+ final int defaultValue = 0x00;
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();
+ final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
service.getFeatures(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
+ } catch (TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
return defaultValue;
@@ -1235,18 +1160,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
public void setPresetName(@NonNull BluetoothDevice device, int presetIndex,
@NonNull String name) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.setPresetName(device, presetIndex, name, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
@@ -1274,18 +1195,14 @@ public final class BluetoothHapClient implements BluetoothProfile, AutoCloseable
})
public void setPresetNameForGroup(int groupId, int presetIndex, @NonNull String name) {
final IBluetoothHapClient service = getService();
- final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
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);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
+ service.setPresetNameForGroup(groupId, presetIndex, name, mAttributionSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/framework/java/android/bluetooth/BluetoothHeadset.java b/framework/java/android/bluetooth/BluetoothHeadset.java
index 4e57c59643..d5af45b172 100644
--- a/framework/java/android/bluetooth/BluetoothHeadset.java
+++ b/framework/java/android/bluetooth/BluetoothHeadset.java
@@ -947,10 +947,21 @@ public final class BluetoothHeadset implements BluetoothProfile {
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
BluetoothStatusCodes.ERROR_TIMEOUT,
+ BluetoothStatusCodes.ERROR_UNKNOWN,
+ })
+ public @interface SetAudioRouteAllowedReturnValues {}
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
BluetoothStatusCodes.ALLOWED,
BluetoothStatusCodes.NOT_ALLOWED,
+ BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
+ BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
+ BluetoothStatusCodes.ERROR_TIMEOUT,
+ BluetoothStatusCodes.ERROR_UNKNOWN,
})
- public @interface AudioRouteAllowedReturnValues {}
+ public @interface GetAudioRouteAllowedReturnValues {}
/**
* Sets whether audio routing is allowed. When set to {@code false}, the AG
@@ -971,7 +982,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioRouteAllowedReturnValues int setAudioRouteAllowed(boolean allowed) {
+ public @SetAudioRouteAllowedReturnValues int setAudioRouteAllowed(boolean allowed) {
if (VDBG) log("setAudioRouteAllowed");
final IBluetoothHeadset service = mService;
if (service == null) {
@@ -1010,7 +1021,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
})
- public @AudioRouteAllowedReturnValues int getAudioRouteAllowed() {
+ public @GetAudioRouteAllowedReturnValues int getAudioRouteAllowed() {
if (VDBG) log("getAudioRouteAllowed");
final IBluetoothHeadset service = mService;
if (service == null) {
diff --git a/framework/java/android/bluetooth/BluetoothUuid.java b/framework/java/android/bluetooth/BluetoothUuid.java
index 5eee4988b1..7847718c5d 100644
--- a/framework/java/android/bluetooth/BluetoothUuid.java
+++ b/framework/java/android/bluetooth/BluetoothUuid.java
@@ -158,9 +158,8 @@ public final class BluetoothUuid {
/** @hide */
@NonNull
@SystemApi
- /* FIXME: Not known yet, using a placeholder instead. */
public static final ParcelUuid HAS =
- ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ ParcelUuid.fromString("00001854-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
@@ -199,6 +198,11 @@ public final class BluetoothUuid {
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid BASS =
+ ParcelUuid.fromString("0000184F-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/system/Android.bp b/system/Android.bp
index df038087c0..f3bbab694e 100644
--- a/system/Android.bp
+++ b/system/Android.bp
@@ -176,7 +176,7 @@ genrule {
"protoc-gen-grpc-python-plugin",
"soong_zip",
],
- cmd: "$(location aprotoc) --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) -Ipackages/modules/Bluetooth/system $(in) --grpc_out=$(genDir) --python_out=$(genDir)",
+ cmd: "$(location aprotoc) --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) -Iexternal/protobuf/src -Ipackages/modules/Bluetooth/system $(in) --grpc_out=$(genDir) --python_out=$(genDir)",
srcs: ["blueberry/facade/topshim/facade.proto"],
out: [
"blueberry/facade/topshim/facade_pb2.py",
diff --git a/system/binder/Android.bp b/system/binder/Android.bp
index 54b7f01be7..44cbc36339 100644
--- a/system/binder/Android.bp
+++ b/system/binder/Android.bp
@@ -25,6 +25,7 @@ filegroup {
"android/bluetooth/IBluetoothHeadset.aidl",
"android/bluetooth/IBluetoothHearingAid.aidl",
"android/bluetooth/IBluetoothHapClient.aidl",
+ "android/bluetooth/IBluetoothHapClientCallback.aidl",
"android/bluetooth/IBluetoothVolumeControl.aidl",
"android/bluetooth/IBluetoothHidHost.aidl",
"android/bluetooth/IBluetoothLeAudio.aidl",
diff --git a/system/binder/android/bluetooth/IBluetoothHapClient.aidl b/system/binder/android/bluetooth/IBluetoothHapClient.aidl
index 672ab409c6..ee956c3210 100644
--- a/system/binder/android/bluetooth/IBluetoothHapClient.aidl
+++ b/system/binder/android/bluetooth/IBluetoothHapClient.aidl
@@ -18,6 +18,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.IBluetoothHapClientCallback;
import android.content.AttributionSource;
import com.android.modules.utils.SynchronousResultReceiver;
@@ -30,10 +31,6 @@ import com.android.modules.utils.SynchronousResultReceiver;
oneway interface IBluetoothHapClient {
// Public API
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void connect(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void disconnect(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getConnectedDevices(in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getDevicesMatchingConnectionStates(in int[] states, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@@ -43,55 +40,46 @@ oneway interface IBluetoothHapClient {
void setConnectionPolicy(in BluetoothDevice device, int connectionPolicy, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getConnectionPolicy(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
-
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getHapGroup(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getActivePresetIndex(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
+ void getActivePresetInfo(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void selectActivePreset(in BluetoothDevice device, int presetIndex, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void selectPreset(in BluetoothDevice device, int presetIndex, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void groupSelectActivePreset(int groupId, int presetIndex, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void selectPresetForGroup(int groupId, int presetIndex, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void nextActivePreset(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void switchToNextPreset(in BluetoothDevice device, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void groupNextActivePreset(int groupId, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void switchToNextPresetForGroup(int groupId, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void previousActivePreset(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void switchToPreviousPreset(in BluetoothDevice device, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void groupPreviousActivePreset(int groupId, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void switchToPreviousPresetForGroup(int groupId, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getPresetInfo(in BluetoothDevice device, int presetIndex, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
- void getAllPresetsInfo(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ void getAllPresetInfo(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)")
void getFeatures(in BluetoothDevice device, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void setPresetName(in BluetoothDevice device, int presetIndex, in String name, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void setPresetName(in BluetoothDevice device, int presetIndex, in String name, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
- void groupSetPresetName(int groupId, int presetIndex, in String name, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ oneway void setPresetNameForGroup(int groupId, int presetIndex, in String name, in AttributionSource attributionSource);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ void registerCallback(in IBluetoothHapClientCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ void unregisterCallback(in IBluetoothHapClientCallback callback, in AttributionSource attributionSource, in SynchronousResultReceiver receiver);
const int PRESET_INDEX_UNAVAILABLE = 0;
const int GROUP_ID_UNAVAILABLE = -1;
- const int STATUS_SET_NAME_NOT_ALLOWED = 1;
- const int STATUS_OPERATION_NOT_SUPPORTED = 2;
- const int STATUS_OPERATION_NOT_POSSIBLE = 3;
- const int STATUS_INVALID_PRESET_NAME_LENGTH = 4;
- const int STATUS_INVALID_PRESET_INDEX = 5;
- const int STATUS_GROUP_OPERATION_NOT_SUPPORTED = 6;
- const int STATUS_PROCEDURE_ALREADY_IN_PROGRESS = 7;
-
const int FEATURE_BIT_NUM_TYPE_MONAURAL = 0;
const int FEATURE_BIT_NUM_TYPE_BANDED = 1;
const int FEATURE_BIT_NUM_SYNCHRONIZATED_PRESETS = 2;
const int FEATURE_BIT_NUM_INDEPENDENT_PRESETS = 3;
const int FEATURE_BIT_NUM_DYNAMIC_PRESETS = 4;
const int FEATURE_BIT_NUM_WRITABLE_PRESETS = 5;
-
- const int PRESET_INFO_REASON_ALL_PRESET_INFO = 0;
- const int PRESET_INFO_REASON_PRESET_INFO_UPDATE = 1;
- const int PRESET_INFO_REASON_PRESET_DELETED = 2;
- const int PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED = 3;
- const int PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE = 4;
}
diff --git a/system/binder/android/bluetooth/IBluetoothHapClientCallback.aidl b/system/binder/android/bluetooth/IBluetoothHapClientCallback.aidl
new file mode 100644
index 0000000000..5e2d8fa30b
--- /dev/null
+++ b/system/binder/android/bluetooth/IBluetoothHapClientCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 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.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapPresetInfo;
+
+import java.util.List;
+
+/**
+ * Callback definitions for interacting with HAP Client service
+ *
+ * @hide
+ */
+oneway interface IBluetoothHapClientCallback {
+ void onActivePresetChanged(in BluetoothDevice device, in int presetIndex);
+ void onSelectActivePresetFailed(in BluetoothDevice device, in int statusCode);
+ void onSelectActivePresetForGroupFailed(in int hapGroupId, in int statusCode);
+ void onPresetInfoChanged(in BluetoothDevice device,
+ in List<BluetoothHapPresetInfo> presetInfoList,
+ in int statusCode);
+ void onHapFeaturesAvailable(in BluetoothDevice device, in int hapFeatures);
+ void onSetPresetNameFailed(in BluetoothDevice device, in int status);
+ void onSetPresetNameForGroupFailed(in int hapGroupId, in int status);
+}
diff --git a/system/blueberry/facade/topshim/facade.proto b/system/blueberry/facade/topshim/facade.proto
index 0414b77b44..9a8679c525 100644
--- a/system/blueberry/facade/topshim/facade.proto
+++ b/system/blueberry/facade/topshim/facade.proto
@@ -1,11 +1,14 @@
syntax = "proto3";
+import "google/protobuf/empty.proto";
+
package blueberry.facade.topshim;
service AdapterService {
rpc FetchEvents(FetchEventsRequest) returns (stream FetchEventsResponse) {}
rpc ToggleStack(ToggleStackRequest) returns (ToggleStackResponse) {}
rpc SetDiscoveryMode(SetDiscoveryModeRequest) returns (SetDiscoveryModeResponse) {}
+ rpc ClearEventFilter(google.protobuf.Empty) returns (google.protobuf.Empty) {}
}
enum EventType {
diff --git a/system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py b/system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py
index 224dffb32a..63e72c58c4 100644
--- a/system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py
+++ b/system/blueberry/tests/gd/rust/topshim/facade/automation_helper.py
@@ -20,6 +20,8 @@ import grpc
from blueberry.facade.topshim import facade_pb2
from blueberry.facade.topshim import facade_pb2_grpc
+from google.protobuf import empty_pb2 as empty_proto
+
class AdapterAutomationHelper():
# Timeout for async wait
@@ -60,6 +62,9 @@ class AdapterAutomationHelper():
async def verify_adapter_started(self):
await asyncio.wait_for(self.pending_future, AdapterAutomationHelper.DEFAULT_TIMEOUT)
+ async def clear_event_filter(self):
+ await self.adapter_stub.ClearEventFilter(empty_proto.Empty())
+
class A2dpAutomationHelper():
"""Invoke gRPC on topshim for A2DP testing"""
diff --git a/system/blueberry/tests/gd/rust/topshim/facade/suspend_test.py b/system/blueberry/tests/gd/rust/topshim/facade/suspend_test.py
new file mode 100644
index 0000000000..d6885bdf31
--- /dev/null
+++ b/system/blueberry/tests/gd/rust/topshim/facade/suspend_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import asyncio
+from mobly import test_runner
+from blueberry.tests.gd.rust.topshim.facade import topshim_base_test
+from blueberry.tests.gd.rust.topshim.facade.automation_helper import AdapterAutomationHelper
+import time
+
+
+class SuspendTest(topshim_base_test.TopshimBaseTest):
+
+ async def _test_verify_event_filter_cleared(self):
+ self.dut_adapter = AdapterAutomationHelper(port=self.dut_port)
+ event_loop = asyncio.get_running_loop()
+ self.dut_adapter.fetch_events(event_loop)
+ self.dut_adapter.pending_future = event_loop.create_future()
+ await self.dut_adapter.clear_event_filter()
+ #TODO(optedoblivion): Replace sleep with a call to LeGetRandom and synchronize on
+ # the callback
+ time.sleep(1)
+ self.dut_adapter.event_handler.cancel()
+
+ def test_verify_event_filter_cleared(self):
+ asyncio.run(self._test_verify_event_filter_cleared())
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/system/bta/ag/bta_ag_act.cc b/system/bta/ag/bta_ag_act.cc
index adf08beafc..1ba68bcc44 100644
--- a/system/bta/ag/bta_ag_act.cc
+++ b/system/bta/ag/bta_ag_act.cc
@@ -373,7 +373,6 @@ void bta_ag_rfc_close(tBTA_AG_SCB* p_scb,
p_scb->codec_fallback = false;
p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
p_scb->role = 0;
- p_scb->post_sco = BTA_AG_POST_SCO_NONE;
p_scb->svc_conn = false;
p_scb->hsp_version = HSP_VERSION_1_2;
bta_ag_at_reinit(&p_scb->at_cb);
diff --git a/system/bta/has/has_client.cc b/system/bta/has/has_client.cc
index 7c6bbdc3c9..044713437f 100644
--- a/system/bta/has/has_client.cc
+++ b/system/bta/has/has_client.cc
@@ -1044,14 +1044,14 @@ class HasClientImpl : public HasClient {
/* Journal update */
device->has_journal_.Append(HasJournalRecord(features, true));
- /* When service is not yet validated, report the available device and
- * notify features otherwise.
+ /* When service is not yet validated, report the available device with
+ * features.
*/
- if (!device->isGattServiceValid()) {
+ if (!device->isGattServiceValid())
callbacks_->OnDeviceAvailable(device->addr, device->GetFeatures());
- } else {
- callbacks_->OnFeaturesUpdate(device->addr, device->GetFeatures());
- }
+
+ /* Notify features */
+ callbacks_->OnFeaturesUpdate(device->addr, device->GetFeatures());
MarkDeviceValidIfInInitialDiscovery(*device);
}
diff --git a/system/bta/has/has_types.h b/system/bta/has/has_types.h
index 89ed82a8ce..d726f07cf7 100644
--- a/system/bta/has/has_types.h
+++ b/system/bta/has/has_types.h
@@ -72,7 +72,7 @@ static_assert(sizeof(HasGattOpContext) <= sizeof(void*));
/* Service UUIDs */
/* FIXME: actually these were not yet assigned - using placeholders for now. */
static const bluetooth::Uuid kUuidHearingAccessService =
- bluetooth::Uuid::From16Bit(0xEEEE);
+ bluetooth::Uuid::From16Bit(0x1854);
static const bluetooth::Uuid kUuidHearingAidFeatures =
bluetooth::Uuid::From16Bit(0xEEED);
static const bluetooth::Uuid kUuidHearingAidPresetControlPoint =
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index c427f50e4e..28abdabf5e 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -95,8 +95,7 @@ const Uuid UUID_VC = Uuid::FromString("1844");
const Uuid UUID_CSIS = Uuid::FromString("1846");
const Uuid UUID_LE_AUDIO = Uuid::FromString("184E");
const Uuid UUID_LE_MIDI = Uuid::FromString("03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
-/* FIXME: Not known yet, using a placeholder instead. */
-const Uuid UUID_HAS = Uuid::FromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+const Uuid UUID_HAS = Uuid::FromString("1854");
const bool enable_address_consolidate = true; // TODO remove
#define COD_MASK 0x07FF
diff --git a/system/build/dpkg/libchrome-822064/debian/README.Debian b/system/build/dpkg/libchrome-822064/debian/README.Debian
deleted file mode 100644
index 773bbf318e..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/README.Debian
+++ /dev/null
@@ -1 +0,0 @@
-libchrome for Debian
diff --git a/system/build/dpkg/libchrome-822064/debian/changelog b/system/build/dpkg/libchrome-822064/debian/changelog
deleted file mode 100644
index 113a5e756a..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-libchrome (822064-1) buster; urgency=low
-
- * Initial release.
-
- -- Sonny Sasaka <sonnysasaka@chromium.org> Fri, 30 Apr 2021 19:41:40 +0000
diff --git a/system/build/dpkg/libchrome-822064/debian/compat b/system/build/dpkg/libchrome-822064/debian/compat
deleted file mode 100644
index f599e28b8a..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/system/build/dpkg/libchrome-822064/debian/control b/system/build/dpkg/libchrome-822064/debian/control
deleted file mode 100644
index b11c23fbc2..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/control
+++ /dev/null
@@ -1,28 +0,0 @@
-Source: libchrome
-Section: libs
-Priority: optional
-Maintainer: Sonny Sasaka <sonnysasaka@chromium.org>
-Standards-Version: 4.1.4
-Homepage: https://chromium.googlesource.com/aosp/platform/external/libchrome/
-Build-Depends:
- debhelper (>=11~),
- clang,
- python3,
- pkg-config,
- ninja-build,
- libglib2.0-dev,
- libevent-dev,
- libnss3-dev,
- libdbus-1-dev,
- libprotobuf-dev,
- googletest,
- libre2-dev,
- libdouble-conversion-dev,
- libssl-dev,
- libabsl-dev
-
-Package: libchrome
-Architecture: any
-Multi-Arch: foreign
-Depends: ${misc:Depends}, ${shlibs:Depends}
-Description: Chromium's base library
diff --git a/system/build/dpkg/libchrome-822064/debian/install_headers.sh b/system/build/dpkg/libchrome-822064/debian/install_headers.sh
deleted file mode 100755
index 7157b1499d..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/install_headers.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-destdir="$1"
-
-header_dirs=(
- base
- base/allocator
- base/containers
- base/debug
- base/files
- base/hash
- base/i18n
- base/json
- base/memory
- base/message_loop
- base/metrics
- base/numerics
- base/posix
- base/process
- base/ranges
- base/strings
- base/synchronization
- base/system
- base/task
- base/task/common
- base/task/sequence_manager
- base/task/thread_pool
- base/test
- base/third_party/icu
- base/third_party/nspr
- base/third_party/valgrind
- base/threading
- base/time
- base/timer
- base/trace_event
- base/trace_event/common
- build
- components/policy
- components/policy/core/common
- testing/gmock/include/gmock
- testing/gtest/include/gtest
- dbus
- third_party/abseil-cpp/absl/types
- )
-
-# Install header files.
-for d in "${header_dirs[@]}" ; do
- mkdir -p "${destdir}/usr/include/libchrome/${d}"
- cp libchrome/"${d}"/*.h "${destdir}/usr/include/libchrome/${d}"
-done
diff --git a/system/build/dpkg/libchrome-822064/debian/libchrome.install b/system/build/dpkg/libchrome-822064/debian/libchrome.install
deleted file mode 100644
index 9d381c1e2b..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/libchrome.install
+++ /dev/null
@@ -1,4 +0,0 @@
-out/Release/lib/libbase*.so /usr/lib
-out/Release/libbase*.a /usr/lib
-out/Release/obj/libchrome/libchrome*.pc /usr/lib/pkgconfig
-usr/include /usr
diff --git a/system/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch b/system/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch
deleted file mode 100644
index a2f2b4b9ad..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/patches/0001-Add-missing-includes.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 50a4636886c958717213856132fcbb57c3b8ea2a Mon Sep 17 00:00:00 2001
-From: Sonny Sasaka <sonnysasaka@chromium.org>
-Date: Fri, 19 Mar 2021 16:18:07 -0700
-Subject: [PATCH] Add missing includes
-
----
- base/hash/md5.cc | 1 +
- crypto/p224_spake.cc | 1 +
- 2 files changed, 2 insertions(+)
-
-diff --git a/libchrome/base/hash/md5.cc b/libchrome/base/hash/md5.cc
-index bdb9990a9..ef8954eaf 100644
---- a/libchrome/base/hash/md5.cc
-+++ b/libchrome/base/hash/md5.cc
-@@ -24,6 +24,7 @@
- #include "base/hash/md5.h"
-
- #include <stddef.h>
-+#include <string.h>
-
- namespace {
-
-diff --git a/libchrome/crypto/p224_spake.cc b/libchrome/crypto/p224_spake.cc
-index 157410537..de0af5466 100644
---- a/libchrome/crypto/p224_spake.cc
-+++ b/libchrome/crypto/p224_spake.cc
-@@ -8,6 +8,7 @@
- #include <crypto/p224_spake.h>
-
- #include <algorithm>
-+#include <string.h>
-
- #include <base/logging.h>
- #include <crypto/p224.h>
---
-2.20.1
-
diff --git a/system/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch b/system/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch
deleted file mode 100644
index 9b359c0e8d..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/patches/0001-rebase_path-for-write_args.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 6875449497baf026fb8228668930a715ffcc7082 Mon Sep 17 00:00:00 2001
-From: Sonny Sasaka <sonnysasaka@chromium.org>
-Date: Fri, 19 Mar 2021 16:56:59 -0700
-Subject: [PATCH] rebase_path for write_args
-
----
- BUILD.gn | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/libchrome/BUILD.gn b/libchrome/BUILD.gn
-index a846d8f52..66ac10a55 100644
---- a/libchrome/BUILD.gn
-+++ b/libchrome/BUILD.gn
-@@ -556,7 +556,7 @@ action("base") {
-
- script = "//common-mk/write_args.py"
- outputs = [ "${root_out_dir}/lib/lib${target_name}.so" ]
-- args = [ "--output" ] + outputs + [ "--" ] + [
-+ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
- "GROUP",
- "(",
- "AS_NEEDED",
-@@ -618,7 +618,7 @@ action("base-test") {
-
- script = "//common-mk/write_args.py"
- outputs = [ "${root_out_dir}/lib${target_name}.a" ]
-- args = [ "--output" ] + outputs + [ "--" ] + [
-+ args = [ "--output" ] + rebase_path(outputs) + [ "--" ] + [
- "GROUP",
- "(",
- "AS_NEEDED",
---
-2.20.1
-
diff --git a/system/build/dpkg/libchrome-822064/debian/patches/series b/system/build/dpkg/libchrome-822064/debian/patches/series
deleted file mode 100644
index 9128588280..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/patches/series
+++ /dev/null
@@ -1,3 +0,0 @@
-0001-Add-missing-includes.patch
-0001-rebase_path-for-write_args.patch
-0001-Remove-absl-from-pkgconfig.patch
diff --git a/system/build/dpkg/libchrome-822064/debian/rules b/system/build/dpkg/libchrome-822064/debian/rules
deleted file mode 100755
index 60b6792048..0000000000
--- a/system/build/dpkg/libchrome-822064/debian/rules
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/make -f
-
-# gn args
-defines =
-defines += pkg_config=\"pkg-config\"
-defines += libbase_ver=\"822064\"
-defines += platform2_root=\"$(shell pwd)/\"
-defines += platform_subdir=\"libchrome\"
-defines += cxx=\"clang++\"
-defines += cc=\"clang\"
-defines += ar=\"ar\"
-defines += external_cxxflags=[\"-DNDEBUG\", \"-I/usr/src/googletest/googletest/include\", \"-I/usr/src/googletest/googlemock/include\", \"-Wno-unknown-warning-option\", \"-Wno-unused-command-line-argument\"]
-defines += external_ldflags=[\"-latomic\", \"-labsl_base\", \"-labsl_bad_variant_access\"]
-defines += enable_werror=false
-defines += libdir=\"/usr/lib\"
-defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false}
-
-# handle parallel build options
-njobs=1
-ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-njobs=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-endif
-
-%:
- dh $@ --parallel
-
-override_dh_auto_build-arch:
- gn gen out/Release --args="$(defines)"
- ninja -j$(njobs) -C out/Release
-
-override_dh_auto_clean:
- rm -rf out
- find . -name \*.pyc -execdir rm -f {} \;
- dh_auto_clean
-
-override_dh_auto_install-arch:
- dh_auto_install
- debian/install_headers.sh debian/tmp
diff --git a/system/build/dpkg/libchrome-822064/gen-src-pkg.sh b/system/build/dpkg/libchrome-822064/gen-src-pkg.sh
deleted file mode 100755
index cbb5dce54a..0000000000
--- a/system/build/dpkg/libchrome-822064/gen-src-pkg.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/bash
-# Generates Debian source and binary packages of libchrome.
-
-if [ -z "$1" ]; then
- echo "Usage: gen-src-pkg.sh <output-dir>"
- exit 1
-fi
-
-outdir="$1"
-pkgdir=libchrome-822064
-origtar=libchrome_822064.orig.tar.gz
-scriptdir="$( cd "$( dirname "$0" )" && pwd )"
-branch=release-R91-13904.B
-
-tmpdir=$(mktemp -d)
-echo Generating source package in "${tmpdir}".
-
-# Download platform2 source.
-cd "${tmpdir}"
-git clone --branch "${branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
-mkdir "${pkgdir}"
-cd "${pkgdir}"
-# Trim platform2, only common-mk is needed.
-cp -a ../platform2/{common-mk,.gn} .
-
-# Download libchrome source and apply Chrome OS's patches.
-git clone --branch "${branch}" https://chromium.googlesource.com/aosp/platform/external/libchrome || exit 1
-cd libchrome
-rm -rf .git
-while read -r patch; do
- patch -p1 < "libchrome_tools/patches/${patch}"
-done < <(grep -E '^[^#]' "libchrome_tools/patches/patches")
-
-# Clean up temporary platform2 checkout.
-cd ../..
-rm -rf platform2
-
-# Debian requires creating .orig.tar.gz.
-tar czf "${origtar}" "${pkgdir}"
-
-# Debianize the source.
-cd "${pkgdir}"
-yes | debmake || exit 1
-cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
-
-# Build source package and binary package.
-cd "${tmpdir}/${pkgdir}"
-dpkg-buildpackage --no-sign || exit 1
-
-# Copy the results to output dir.
-cd "${tmpdir}"
-mkdir -p "${outdir}/src"
-cp *.dsc *.orig.tar.gz *.debian.tar.xz "${outdir}/src"
-cp *.deb "${outdir}"
-cd /
-
-echo Removing temporary directory "${tmpdir}".
-rm -rf "${tmpdir}"
-
-echo Done. Check out Debian source package in "${outdir}".
diff --git a/system/build/dpkg/libchrome/debian/changelog b/system/build/dpkg/libchrome/debian/changelog
index 3cdedf6890..e8985eae22 100644
--- a/system/build/dpkg/libchrome/debian/changelog
+++ b/system/build/dpkg/libchrome/debian/changelog
@@ -1,5 +1,5 @@
-libchrome (780652-1) buster; urgency=low
+libchrome (930012-1) bullseye; urgency=low
- * Initial release.
+ * Upgrade to BASE_VER = 930012
- -- Sonny Sasaka <sonnysasaka@chromium.org> Fri, 19 Mar 2021 19:41:40 +0000
+ -- Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Fri, 11 Feb 2022 14:56:00 +0000
diff --git a/system/build/dpkg/libchrome/debian/control b/system/build/dpkg/libchrome/debian/control
index d804b4d88d..b11c23fbc2 100644
--- a/system/build/dpkg/libchrome/debian/control
+++ b/system/build/dpkg/libchrome/debian/control
@@ -18,7 +18,8 @@ Build-Depends:
googletest,
libre2-dev,
libdouble-conversion-dev,
- libssl-dev
+ libssl-dev,
+ libabsl-dev
Package: libchrome
Architecture: any
diff --git a/system/build/dpkg/libchrome/debian/install_headers.sh b/system/build/dpkg/libchrome/debian/install_headers.sh
index 19cb5efa80..817f1a6efc 100755
--- a/system/build/dpkg/libchrome/debian/install_headers.sh
+++ b/system/build/dpkg/libchrome/debian/install_headers.sh
@@ -5,9 +5,12 @@ destdir="$1"
header_dirs=(
base
base/allocator
+ base/allocator/partition_allocator
+ base/allocator/partition_allocator/starscan
base/containers
base/debug
base/files
+ base/functional
base/hash
base/i18n
base/json
@@ -17,6 +20,7 @@ header_dirs=(
base/numerics
base/posix
base/process
+ base/ranges
base/strings
base/synchronization
base/system
@@ -33,13 +37,18 @@ header_dirs=(
base/timer
base/trace_event
base/trace_event/common
+ base/types
build
components/policy
components/policy/core/common
testing/gmock/include/gmock
testing/gtest/include/gtest
dbus
- )
+ third_party/abseil-cpp/absl/types
+ third_party/perfetto/include/perfetto/tracing/
+ third_party/perfetto/include/perfetto/protozero/
+ third_party/perfetto/protos/perfetto/trace/track_event/
+)
# Install header files.
for d in "${header_dirs[@]}" ; do
diff --git a/system/build/dpkg/libchrome/debian/libchrome.install.docker b/system/build/dpkg/libchrome/debian/libchrome.install.docker
new file mode 100644
index 0000000000..b4034e7457
--- /dev/null
+++ b/system/build/dpkg/libchrome/debian/libchrome.install.docker
@@ -0,0 +1,5 @@
+out/Release/lib/libbase*.so /usr/lib/x86_64-linux-gnu
+out/Release/libbase*.a /usr/lib/x86_64-linux-gnu
+out/Release/obj/libchrome/libchrome*.pc /usr/lib/x86_64-linux-gnu/pkgconfig
+usr/include /usr
+
diff --git a/system/build/dpkg/libchrome/debian/patches/0001-Fix-build-issues-on-930012.patch b/system/build/dpkg/libchrome/debian/patches/0001-Fix-build-issues-on-930012.patch
new file mode 100644
index 0000000000..61d044b4fb
--- /dev/null
+++ b/system/build/dpkg/libchrome/debian/patches/0001-Fix-build-issues-on-930012.patch
@@ -0,0 +1,37 @@
+From 1153211a5615156f450a4f521da284a7df4d4e5f Mon Sep 17 00:00:00 2001
+From: Abhishek Pandit-Subedi <abhishekpandit@google.com>
+Date: Mon, 14 Feb 2022 14:40:41 -0800
+Subject: [PATCH] Fix build issues on 930012
+
+---
+ BUILD.gn | 1 +
+ base/command_line.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/libchrome/BUILD.gn b/libchrome/BUILD.gn
+index 292c08565a..dbe3fb0981 100644
+--- a/libchrome/BUILD.gn
++++ b/libchrome/BUILD.gn
+@@ -42,6 +42,7 @@ config("libchrome_config") {
+ "-Wno-unreachable-code-return",
+ "-Wno-unused-local-typedefs",
+ "-Xclang-only=-Wno-char-subscripts",
++ "-Wno-implicit-int-float-conversion",
+ ]
+
+ # Address sanitizer + coverage builds do not support -z,defs.
+diff --git a/libchrome/base/command_line.h b/libchrome/base/command_line.h
+index 706726a73e..ad0281283a 100644
+--- a/libchrome/base/command_line.h
++++ b/libchrome/base/command_line.h
+@@ -19,6 +19,7 @@
+ #include <stddef.h>
+ #include <functional>
+ #include <map>
++#include <memory>
+ #include <string>
+ #include <vector>
+
+--
+2.35.1.265.g69c8d7142f-goog
+
diff --git a/system/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch b/system/build/dpkg/libchrome/debian/patches/0001-Remove-absl-from-pkgconfig.patch
index 73b8c48cd6..73b8c48cd6 100644
--- a/system/build/dpkg/libchrome-822064/debian/patches/0001-Remove-absl-from-pkgconfig.patch
+++ b/system/build/dpkg/libchrome/debian/patches/0001-Remove-absl-from-pkgconfig.patch
diff --git a/system/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch b/system/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
deleted file mode 100644
index 418efcc475..0000000000
--- a/system/build/dpkg/libchrome/debian/patches/0001-common-mk-rebase_path-output-location-of-generate-pc.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 04fa5e1ade08696b5a2cc3b65bf0fd26c43251c7 Mon Sep 17 00:00:00 2001
-From: Sonny Sasaka <sonnysasaka@chromium.org>
-Date: Fri, 19 Mar 2021 11:17:43 -0700
-Subject: [PATCH] common-mk: rebase_path output location of generate-pc.py
-
-Without rebase_path, the generate-pc.py would be called like
-`generate-pc.py --output //out/Release` if the output is inside the
-source directory and this gn path isn't recognized as a generic
-filesystem path.
-
-BUG=b:183216216
-TEST=with modp_b64, call
-$ gn gen out/Release --args=...
-$ ninja
-
-Change-Id: Ic9d9b3d01d52d483e3d81ca2e8d514b47900f5bb
----
- common-mk/pkg_config.gni | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/common-mk/pkg_config.gni b/common-mk/pkg_config.gni
-index 24e2cf1401..b2c58845d4 100644
---- a/common-mk/pkg_config.gni
-+++ b/common-mk/pkg_config.gni
-@@ -84,7 +84,7 @@ template("generate_pkg_config") {
- outputs = [ "${target_out_dir}/${output_name}.pc" ]
-
- script = "//common-mk/generate-pc.py"
-- args = [ "--output" ] + outputs + [ "--name=" + name ]
-+ args = [ "--output" ] + rebase_path(outputs) + [ "--name=" + name ]
- if (defined(description)) {
- args += [ "--description=" + description ]
- }
---
-2.29.2
-
diff --git a/system/build/dpkg/libchrome/debian/patches/series b/system/build/dpkg/libchrome/debian/patches/series
index 5a26f7be70..de8be97780 100644
--- a/system/build/dpkg/libchrome/debian/patches/series
+++ b/system/build/dpkg/libchrome/debian/patches/series
@@ -1,3 +1,4 @@
-0001-common-mk-rebase_path-output-location-of-generate-pc.patch
0001-Add-missing-includes.patch
0001-rebase_path-for-write_args.patch
+0001-Remove-absl-from-pkgconfig.patch
+0001-Fix-build-issues-on-930012.patch
diff --git a/system/build/dpkg/libchrome/debian/rules b/system/build/dpkg/libchrome/debian/rules
index 6ac17835c4..3374099c98 100755
--- a/system/build/dpkg/libchrome/debian/rules
+++ b/system/build/dpkg/libchrome/debian/rules
@@ -3,17 +3,17 @@
# gn args
defines =
defines += pkg_config=\"pkg-config\"
-defines += libbase_ver=\"780652\"
+defines += libbase_ver=\"930012\"
defines += platform2_root=\"$(shell pwd)/\"
defines += platform_subdir=\"libchrome\"
defines += cxx=\"clang++\"
defines += cc=\"clang\"
defines += ar=\"ar\"
-defines += external_cxxflags=[\"-I/usr/src/googletest/googletest/include\", \"-I/usr/src/googletest/googlemock/include\"]
-defines += external_ldflags=[\"-latomic\"]
+defines += external_cxxflags=[\"-DNDEBUG\", \"-I/usr/src/googletest/googletest/include\", \"-I/usr/src/googletest/googlemock/include\", \"-Wno-unknown-warning-option\", \"-Wno-unused-command-line-argument\", \"-Wno-implicit-int-float-conversion\"]
+defines += external_ldflags=[\"-latomic\", \"-labsl_base\", \"-labsl_bad_variant_access\", \"-labsl_bad_optional_access\"]
defines += enable_werror=false
defines += libdir=\"/usr/lib\"
-defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false}
+defines += use={mojo=false asan=false coverage=false crypto=true dbus=true fuzzer=false timers=true cros_host=false profiling=false tcmalloc=false test=false}
# handle parallel build options
njobs=1
diff --git a/system/build/dpkg/libchrome/gen-src-pkg.sh b/system/build/dpkg/libchrome/gen-src-pkg.sh
index 3cee0e4612..01390f126d 100755
--- a/system/build/dpkg/libchrome/gen-src-pkg.sh
+++ b/system/build/dpkg/libchrome/gen-src-pkg.sh
@@ -7,25 +7,34 @@ if [ -z "$1" ]; then
fi
outdir="$1"
-pkgdir=libchrome-780652
-origtar=libchrome_780652.orig.tar.gz
+pkgdir=libchrome-930012
+origtar=libchrome_930012.orig.tar.gz
scriptdir="$( cd "$( dirname "$0" )" && pwd )"
-branch=release-R90-13816.B
+
+# Pin the libchrome branch + commit
+libchrome_branch=master
+libchrome_commit=4b86c42f09b7c8d88b0233c60f59bafeb4d8df19
+
+# Pin the platform2 branch + commit
+platform2_branch=main
+platform2_commit=4567e833015453b3ea322eec1201cc41ecdfdec0
tmpdir=$(mktemp -d)
echo Generating source package in "${tmpdir}".
# Download platform2 source.
cd "${tmpdir}"
-git clone --branch "${branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
+git clone --branch "${platform2_branch}" https://chromium.googlesource.com/chromiumos/platform2 || exit 1
+(cd platform2 && git checkout "${platform2_commit}")
mkdir "${pkgdir}"
cd "${pkgdir}"
# Trim platform2, only common-mk is needed.
cp -a ../platform2/{common-mk,.gn} .
# Download libchrome source and apply Chrome OS's patches.
-git clone --branch "${branch}" https://chromium.googlesource.com/aosp/platform/external/libchrome || exit 1
+git clone --branch "${libchrome_branch}" https://chromium.googlesource.com/aosp/platform/external/libchrome || exit 1
cd libchrome
+git checkout "${libchrome_commit}"
rm -rf .git
while read -r patch; do
patch -p1 < "libchrome_tools/patches/${patch}"
@@ -43,6 +52,14 @@ cd "${pkgdir}"
yes | debmake || exit 1
cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
+# If building for docker, use the right install script.
+if [ ! -z "${LIBCHROME_DOCKER}" ]; then
+ mv "${tmpdir}/${pkgdir}/debian/libchrome.install.docker" \
+ "${tmpdir}/${pkgdir}/debian/libchrome.install"
+else
+ rm -f "${tmpdir}/${pkgdir}/debian/libchrome.install.docker"
+fi
+
# Build source package and binary package.
cd "${tmpdir}/${pkgdir}"
dpkg-buildpackage --no-sign || exit 1
diff --git a/system/build/dpkg/modp_b64/debian/modp-b64.install.docker b/system/build/dpkg/modp_b64/debian/modp-b64.install.docker
new file mode 100644
index 0000000000..a028ca4955
--- /dev/null
+++ b/system/build/dpkg/modp_b64/debian/modp-b64.install.docker
@@ -0,0 +1,3 @@
+modp_b64/modp_b64 /usr/include
+out/Release/libmodp_b64.a /usr/lib/x86_64-linux-gnu
+out/Release/obj/modp_b64/libmodp_b64.pc /usr/lib/x86_64-linux-gnu/pkgconfig
diff --git a/system/build/dpkg/modp_b64/gen-src-pkg.sh b/system/build/dpkg/modp_b64/gen-src-pkg.sh
index cc22f678f2..5e62160159 100755
--- a/system/build/dpkg/modp_b64/gen-src-pkg.sh
+++ b/system/build/dpkg/modp_b64/gen-src-pkg.sh
@@ -40,6 +40,15 @@ cd "${pkgdir}"
yes | debmake || exit 1
cp -aT "${scriptdir}/debian/" "${tmpdir}/${pkgdir}/debian/"
+# If building for docker, use the right install script.
+if [ ! -z "${MODP_DOCKER}" ]; then
+ mv "${tmpdir}/${pkgdir}/debian/modp-b64.install.docker" \
+ "${tmpdir}/${pkgdir}/debian/modp-b64.install"
+else
+ rm -f "${tmpdir}/${pkgdir}/debian/modp-b64.install.docker"
+fi
+
+
# Build source package and binary package.
cd "${tmpdir}/${pkgdir}"
dpkg-buildpackage --no-sign || exit 1
diff --git a/system/gd/cert/run_topshim b/system/gd/cert/run_topshim
index 50a01343df..a2c04848c4 100755
--- a/system/gd/cert/run_topshim
+++ b/system/gd/cert/run_topshim
@@ -20,7 +20,8 @@ import os
import argparse
TEST_SUITES = [
- "blueberry.tests.gd.rust.topshim.facade.adapter_test"
+ "blueberry.tests.gd.rust.topshim.facade.adapter_test",
+ "blueberry.tests.gd.rust.topshim.facade.suspend_test"
]
SOONG_UI_BASH = 'build/soong/soong_ui.bash'
@@ -135,7 +136,7 @@ def main():
if not all(test_results):
failures = [i for i, x in enumerate(test_results) if not x]
for index in failures:
- print('TEST FAILLED: ' + TEST_SUITES[index])
+ print('TEST FAILED: ' + TEST_SUITES[index])
sys.exit(0)
print('TEST PASSED ' + str(len(test_results)) + ' tests were run')
diff --git a/system/gd/rust/topshim/facade/src/adapter_service.rs b/system/gd/rust/topshim/facade/src/adapter_service.rs
index efd96eebd4..1243b07b16 100644
--- a/system/gd/rust/topshim/facade/src/adapter_service.rs
+++ b/system/gd/rust/topshim/facade/src/adapter_service.rs
@@ -3,6 +3,7 @@
use bt_topshim::btif;
use bt_topshim::btif::{BaseCallbacks, BaseCallbacksDispatcher, BluetoothInterface};
+use bt_topshim_facade_protobuf::empty::Empty;
use bt_topshim_facade_protobuf::facade::{
EventType, FetchEventsRequest, FetchEventsResponse, SetDiscoveryModeRequest,
SetDiscoveryModeResponse, ToggleStackRequest, ToggleStackResponse,
@@ -118,4 +119,11 @@ impl AdapterService for AdapterServiceImpl {
sink.success(SetDiscoveryModeResponse::default()).await.unwrap();
})
}
+
+ fn clear_event_filter(&mut self, ctx: RpcContext<'_>, _req: Empty, sink: UnarySink<Empty>) {
+ self.btif_intf.lock().unwrap().clear_event_filter();
+ ctx.spawn(async move {
+ sink.success(Empty::default()).await.unwrap();
+ })
+ }
}
diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs
index 6b76eac797..9febbaca3c 100644
--- a/system/gd/rust/topshim/src/btif.rs
+++ b/system/gd/rust/topshim/src/btif.rs
@@ -1004,6 +1004,10 @@ impl BluetoothInterface {
ccall!(self, ssp_reply, ffi_addr, cvariant, accept, passkey)
}
+ pub fn clear_event_filter(&self) -> i32 {
+ ccall!(self, clear_event_filter)
+ }
+
pub(crate) fn get_profile_interface(
&self,
profile: SupportedProfiles,
diff --git a/system/include/hardware/bt_has.h b/system/include/hardware/bt_has.h
index 4fdd316852..739edc041f 100644
--- a/system/include/hardware/bt_has.h
+++ b/system/include/hardware/bt_has.h
@@ -36,9 +36,10 @@ enum class ConnectionState : uint8_t {
/** Results codes for the failed preset operations */
enum class ErrorCode : uint8_t {
NO_ERROR = 0,
- SET_NAME_NOT_ALLOWED,
- OPERATION_NOT_SUPPORTED,
- OPERATION_NOT_POSSIBLE,
+ SET_NAME_NOT_ALLOWED, // Preset cannot be written (read only preset)
+ OPERATION_NOT_SUPPORTED, // If theres no optional characteristic,
+ // or request opcode is invalid or not supported
+ OPERATION_NOT_POSSIBLE, // Operation cannot be performed at this time
INVALID_PRESET_NAME_LENGTH,
INVALID_PRESET_INDEX,
GROUP_OPERATION_NOT_SUPPORTED,
diff --git a/system/stack/btm/btm_iso_impl.h b/system/stack/btm/btm_iso_impl.h
index dafd76b689..e9cd6e8287 100644
--- a/system/stack/btm/btm_iso_impl.h
+++ b/system/stack/btm/btm_iso_impl.h
@@ -316,7 +316,7 @@ struct iso_impl {
void remove_iso_data_path(uint16_t iso_handle, uint8_t data_path_dir) {
iso_base* iso = GetIsoIfKnown(iso_handle);
- LOG_ASSERT(iso != nullptr) << "No such iso connection: " << +iso_handle;
+ LOG_ASSERT(iso != nullptr) << "No such iso connection: " << loghex(iso_handle);
LOG_ASSERT((iso->state_flags & kStateFlagHasDataPathSet) ==
kStateFlagHasDataPathSet)
<< "Data path not set";
@@ -373,7 +373,7 @@ struct iso_impl {
void read_iso_link_quality(uint16_t iso_handle) {
iso_base* iso = GetIsoIfKnown(iso_handle);
if (iso == nullptr) {
- LOG(ERROR) << __func__ << "No such iso connection: " << +iso_handle;
+ LOG(ERROR) << __func__ << "No such iso connection: " << loghex(iso_handle);
return;
}
@@ -416,14 +416,17 @@ struct iso_impl {
uint16_t data_len) {
iso_base* iso = GetIsoIfKnown(iso_handle);
LOG_ASSERT(iso != nullptr)
- << "No such iso connection handle: " << +iso_handle;
+ << "No such iso connection handle: " << loghex(iso_handle);
if (!(iso->state_flags & kStateFlagIsBroadcast)) {
- LOG_ASSERT(iso->state_flags & kStateFlagIsConnected)
- << "CIS not established";
+ if (!(iso->state_flags & kStateFlagIsConnected)) {
+ LOG(WARNING) << __func__ << "Cis handle: " << loghex(iso_handle)
+ << " not established";
+ return;
+ }
}
LOG_ASSERT(iso->state_flags & kStateFlagHasDataPathSet)
- << "Data path not set for handle: " << +iso_handle;
+ << "Data path not set for handle: " << loghex(iso_handle);
/* Calculate sequence number for the ISO data packet.
* It should be incremented by 1 every SDU Interval.
diff --git a/system/stack/test/btm_iso_test.cc b/system/stack/test/btm_iso_test.cc
index bae5c005a5..f4984296f7 100644
--- a/system/stack/test/btm_iso_test.cc
+++ b/system/stack/test/btm_iso_test.cc
@@ -1805,6 +1805,17 @@ TEST_F(IsoManagerTest, RemoveIsoDataPathInvalidStatus) {
iso_handle, kDefaultIsoDataPathParams.data_path_dir);
}
+TEST_F(IsoManagerTest, SendIsoDataWithNoCigConnected) {
+ std::vector<uint8_t> data_vec(108, 0);
+ IsoManager::GetInstance()->CreateCig(
+ volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
+
+ auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
+ IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(),
+ data_vec.size());
+ EXPECT_CALL(bte_interface_, HciSend).Times(0);
+}
+
TEST_F(IsoManagerTest, SendIsoDataCigValid) {
IsoManager::GetInstance()->CreateCig(
volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
@@ -2137,17 +2148,6 @@ TEST_F(IsoManagerDeathTest, SendIsoDataWithNoCigBigHandle) {
::testing::KilledBySignal(SIGABRT), "No such iso");
}
-TEST_F(IsoManagerDeathTest, SendIsoDataWithNoCigConnected) {
- std::vector<uint8_t> data_vec(108, 0);
- IsoManager::GetInstance()->CreateCig(
- volatile_test_cig_create_cmpl_evt_.cig_id, kDefaultCigParams);
-
- auto handle = volatile_test_cig_create_cmpl_evt_.conn_handles[0];
- ASSERT_EXIT(IsoManager::GetInstance()->SendIsoData(handle, data_vec.data(),
- data_vec.size()),
- ::testing::KilledBySignal(SIGABRT), "CIS not established");
-}
-
TEST_F(IsoManagerTest, HandleDisconnectNoSuchHandle) {
// Don't expect any callbacks when connection handle is not for ISO.
EXPECT_CALL(*cig_callbacks_, OnCigEvent).Times(0);
diff --git a/system/vendor_libs/test_vendor_lib/net/posix/posix_async_socket.cc b/system/vendor_libs/test_vendor_lib/net/posix/posix_async_socket.cc
index c5e8af3a94..1d57d10f34 100644
--- a/system/vendor_libs/test_vendor_lib/net/posix/posix_async_socket.cc
+++ b/system/vendor_libs/test_vendor_lib/net/posix/posix_async_socket.cc
@@ -41,7 +41,7 @@ PosixAsyncSocket::PosixAsyncSocket(int fd, AsyncManager* am)
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
flags = fcntl(fd, F_GETFD);
- fcntl(fd, F_SETFD, flags | O_CLOEXEC);
+ fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
#ifdef SO_NOSIGPIPE
// Disable SIGPIPE generation on Darwin.