Loading android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java +37 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.gatt; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUtils; Loading @@ -29,6 +31,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; Loading @@ -50,12 +53,13 @@ public class DistanceMeasurementManager { private static final int CS_HIGH_FREQUENCY_INTERVAL_MS = 200; private final AdapterService mAdapterService; private HandlerThread mHandlerThread; private final HandlerThread mHandlerThread; DistanceMeasurementNativeInterface mDistanceMeasurementNativeInterface; private final ConcurrentHashMap<String, CopyOnWriteArraySet<DistanceMeasurementTracker>> mRssiTrackers = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, CopyOnWriteArraySet<DistanceMeasurementTracker>> mCsTrackers = new ConcurrentHashMap<>(); private final boolean mHasChannelSoundingFeature; /** Constructor of {@link DistanceMeasurementManager}. */ DistanceMeasurementManager(AdapterService adapterService) { Loading @@ -66,6 +70,14 @@ public class DistanceMeasurementManager { mHandlerThread.start(); mDistanceMeasurementNativeInterface = DistanceMeasurementNativeInterface.getInstance(); mDistanceMeasurementNativeInterface.init(this); if (Flags.channelSounding25q2Apis()) { mHasChannelSoundingFeature = adapterService .getPackageManager() .hasSystemFeature(FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING); } else { mHasChannelSoundingFeature = true; } } void cleanup() { Loading @@ -78,14 +90,14 @@ public class DistanceMeasurementManager { new DistanceMeasurementMethod.Builder( DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI) .build()); if (mAdapterService.isLeChannelSoundingSupported()) { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { methods.add( new DistanceMeasurementMethod.Builder( DistanceMeasurementMethod .DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING) .build()); } return methods.toArray(new DistanceMeasurementMethod[methods.size()]); return methods.toArray(new DistanceMeasurementMethod[0]); } void startDistanceMeasurement( Loading Loading @@ -121,8 +133,16 @@ public class DistanceMeasurementManager { startRssiTracker(tracker); break; case DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING: if (!mAdapterService.isLeChannelSoundingSupported() || !mAdapterService.isConnected(params.getDevice())) { if (!mHasChannelSoundingFeature || !mAdapterService.isLeChannelSoundingSupported()) { Log.e(TAG, "Channel Sounding is not supported."); invokeStartFail( callback, params.getDevice(), BluetoothStatusCodes.FEATURE_NOT_SUPPORTED); return; } if (!mAdapterService.isConnected(params.getDevice())) { Log.e(TAG, "Device " + params.getDevice() + " is not connected"); invokeStartFail( callback, Loading Loading @@ -196,17 +216,26 @@ public class DistanceMeasurementManager { } int getChannelSoundingMaxSupportedSecurityLevel(BluetoothDevice remoteDevice) { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return ChannelSoundingParams.CS_SECURITY_LEVEL_ONE; } return ChannelSoundingParams.CS_SECURITY_LEVEL_UNKNOWN; } int getLocalChannelSoundingMaxSupportedSecurityLevel() { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return ChannelSoundingParams.CS_SECURITY_LEVEL_ONE; } return ChannelSoundingParams.CS_SECURITY_LEVEL_UNKNOWN; } Set<Integer> getChannelSoundingSupportedSecurityLevels() { // TODO(b/378685103): get it from the HAL when level 4 is supported and HAL v2 is available. if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return Set.of(ChannelSoundingParams.CS_SECURITY_LEVEL_ONE); } throw new UnsupportedOperationException("Channel Sounding is not supported."); } private synchronized int stopRssiTracker(UUID uuid, String identityAddress, boolean timeout) { CopyOnWriteArraySet<DistanceMeasurementTracker> set = mRssiTrackers.get(identityAddress); Loading android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.bluetooth.gatt; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.after; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; Loading @@ -30,6 +31,7 @@ import android.bluetooth.le.DistanceMeasurementMethod; import android.bluetooth.le.DistanceMeasurementParams; import android.bluetooth.le.DistanceMeasurementResult; import android.bluetooth.le.IDistanceMeasurementCallback; import android.content.pm.PackageManager; import android.os.RemoteException; import androidx.test.filters.SmallTest; Loading Loading @@ -57,6 +59,7 @@ public class DistanceMeasurementManagerTest { @Mock private DistanceMeasurementNativeInterface mDistanceMeasurementNativeInterface; @Mock private AdapterService mAdapterService; @Mock private PackageManager mPackageManager; @Mock private IDistanceMeasurementCallback mCallback; private DistanceMeasurementManager mDistanceMeasurementManager; private UUID mUuid; Loading @@ -67,6 +70,8 @@ public class DistanceMeasurementManagerTest { @Before public void setUp() throws Exception { doReturn(mPackageManager).when(mAdapterService).getPackageManager(); doReturn(true).when(mPackageManager).hasSystemFeature(any()); doReturn(IDENTITY_ADDRESS).when(mAdapterService).getIdentityAddress(IDENTITY_ADDRESS); DistanceMeasurementNativeInterface.setInstance(mDistanceMeasurementNativeInterface); mDistanceMeasurementManager = new DistanceMeasurementManager(mAdapterService); Loading Loading
android/app/src/com/android/bluetooth/gatt/DistanceMeasurementManager.java +37 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.gatt; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothStatusCodes; import android.bluetooth.BluetoothUtils; Loading @@ -29,6 +31,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; Loading @@ -50,12 +53,13 @@ public class DistanceMeasurementManager { private static final int CS_HIGH_FREQUENCY_INTERVAL_MS = 200; private final AdapterService mAdapterService; private HandlerThread mHandlerThread; private final HandlerThread mHandlerThread; DistanceMeasurementNativeInterface mDistanceMeasurementNativeInterface; private final ConcurrentHashMap<String, CopyOnWriteArraySet<DistanceMeasurementTracker>> mRssiTrackers = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, CopyOnWriteArraySet<DistanceMeasurementTracker>> mCsTrackers = new ConcurrentHashMap<>(); private final boolean mHasChannelSoundingFeature; /** Constructor of {@link DistanceMeasurementManager}. */ DistanceMeasurementManager(AdapterService adapterService) { Loading @@ -66,6 +70,14 @@ public class DistanceMeasurementManager { mHandlerThread.start(); mDistanceMeasurementNativeInterface = DistanceMeasurementNativeInterface.getInstance(); mDistanceMeasurementNativeInterface.init(this); if (Flags.channelSounding25q2Apis()) { mHasChannelSoundingFeature = adapterService .getPackageManager() .hasSystemFeature(FEATURE_BLUETOOTH_LE_CHANNEL_SOUNDING); } else { mHasChannelSoundingFeature = true; } } void cleanup() { Loading @@ -78,14 +90,14 @@ public class DistanceMeasurementManager { new DistanceMeasurementMethod.Builder( DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI) .build()); if (mAdapterService.isLeChannelSoundingSupported()) { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { methods.add( new DistanceMeasurementMethod.Builder( DistanceMeasurementMethod .DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING) .build()); } return methods.toArray(new DistanceMeasurementMethod[methods.size()]); return methods.toArray(new DistanceMeasurementMethod[0]); } void startDistanceMeasurement( Loading Loading @@ -121,8 +133,16 @@ public class DistanceMeasurementManager { startRssiTracker(tracker); break; case DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_CHANNEL_SOUNDING: if (!mAdapterService.isLeChannelSoundingSupported() || !mAdapterService.isConnected(params.getDevice())) { if (!mHasChannelSoundingFeature || !mAdapterService.isLeChannelSoundingSupported()) { Log.e(TAG, "Channel Sounding is not supported."); invokeStartFail( callback, params.getDevice(), BluetoothStatusCodes.FEATURE_NOT_SUPPORTED); return; } if (!mAdapterService.isConnected(params.getDevice())) { Log.e(TAG, "Device " + params.getDevice() + " is not connected"); invokeStartFail( callback, Loading Loading @@ -196,17 +216,26 @@ public class DistanceMeasurementManager { } int getChannelSoundingMaxSupportedSecurityLevel(BluetoothDevice remoteDevice) { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return ChannelSoundingParams.CS_SECURITY_LEVEL_ONE; } return ChannelSoundingParams.CS_SECURITY_LEVEL_UNKNOWN; } int getLocalChannelSoundingMaxSupportedSecurityLevel() { if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return ChannelSoundingParams.CS_SECURITY_LEVEL_ONE; } return ChannelSoundingParams.CS_SECURITY_LEVEL_UNKNOWN; } Set<Integer> getChannelSoundingSupportedSecurityLevels() { // TODO(b/378685103): get it from the HAL when level 4 is supported and HAL v2 is available. if (mHasChannelSoundingFeature && mAdapterService.isLeChannelSoundingSupported()) { return Set.of(ChannelSoundingParams.CS_SECURITY_LEVEL_ONE); } throw new UnsupportedOperationException("Channel Sounding is not supported."); } private synchronized int stopRssiTracker(UUID uuid, String identityAddress, boolean timeout) { CopyOnWriteArraySet<DistanceMeasurementTracker> set = mRssiTrackers.get(identityAddress); Loading
android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementManagerTest.java +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.bluetooth.gatt; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.after; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; Loading @@ -30,6 +31,7 @@ import android.bluetooth.le.DistanceMeasurementMethod; import android.bluetooth.le.DistanceMeasurementParams; import android.bluetooth.le.DistanceMeasurementResult; import android.bluetooth.le.IDistanceMeasurementCallback; import android.content.pm.PackageManager; import android.os.RemoteException; import androidx.test.filters.SmallTest; Loading Loading @@ -57,6 +59,7 @@ public class DistanceMeasurementManagerTest { @Mock private DistanceMeasurementNativeInterface mDistanceMeasurementNativeInterface; @Mock private AdapterService mAdapterService; @Mock private PackageManager mPackageManager; @Mock private IDistanceMeasurementCallback mCallback; private DistanceMeasurementManager mDistanceMeasurementManager; private UUID mUuid; Loading @@ -67,6 +70,8 @@ public class DistanceMeasurementManagerTest { @Before public void setUp() throws Exception { doReturn(mPackageManager).when(mAdapterService).getPackageManager(); doReturn(true).when(mPackageManager).hasSystemFeature(any()); doReturn(IDENTITY_ADDRESS).when(mAdapterService).getIdentityAddress(IDENTITY_ADDRESS); DistanceMeasurementNativeInterface.setInstance(mDistanceMeasurementNativeInterface); mDistanceMeasurementManager = new DistanceMeasurementManager(mAdapterService); Loading