/* * Copyright (C) 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 com.android.server.uwb; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static com.android.modules.utils.build.SdkLevel.isAtLeastV; import static com.android.server.uwb.UwbSessionManager.SESSION_OPEN_RANGING; import static com.android.server.uwb.UwbTestUtils.DATA_PAYLOAD; import static com.android.server.uwb.UwbTestUtils.MAX_DATA_SIZE; import static com.android.server.uwb.UwbTestUtils.PEER_BAD_MAC_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_MAC_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_MAC_ADDRESS_2; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_MAC_ADDRESS_2_LONG; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_MAC_ADDRESS_LONG; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_SHORT_MAC_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_SHORT_MAC_ADDRESS_LONG; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_SHORT_UWB_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_UWB_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_EXTENDED_UWB_ADDRESS_2; import static com.android.server.uwb.UwbTestUtils.PEER_SHORT_MAC_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PEER_SHORT_MAC_ADDRESS_LONG; import static com.android.server.uwb.UwbTestUtils.PEER_SHORT_UWB_ADDRESS; import static com.android.server.uwb.UwbTestUtils.PERSISTABLE_BUNDLE; import static com.android.server.uwb.UwbTestUtils.RANGING_MEASUREMENT_TYPE_UNDEFINED; import static com.android.server.uwb.UwbTestUtils.TEST_SESSION_ID; import static com.android.server.uwb.UwbTestUtils.TEST_SESSION_ID_2; import static com.android.server.uwb.UwbTestUtils.TEST_SESSION_TYPE; import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_EXTENDED; import static com.android.server.uwb.data.UwbUciConstants.MAC_ADDRESSING_MODE_SHORT; import static com.android.server.uwb.data.UwbUciConstants.RANGING_DEVICE_ROLE_ADVERTISER; import static com.android.server.uwb.data.UwbUciConstants.RANGING_DEVICE_ROLE_OBSERVER; import static com.android.server.uwb.data.UwbUciConstants.RANGING_MEASUREMENT_TYPE_OWR_AOA; import static com.android.server.uwb.data.UwbUciConstants.RANGING_MEASUREMENT_TYPE_TWO_WAY; import static com.android.server.uwb.data.UwbUciConstants.ROUND_USAGE_DS_TWR_DEFERRED_MODE; import static com.android.server.uwb.data.UwbUciConstants.ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE; import static com.android.server.uwb.data.UwbUciConstants.ROUND_USAGE_OWR_AOA_MEASUREMENT; import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_DATA_TRANSFER_ERROR_DATA_TRANSFER; import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_DATA_TRANSFER_OK; import static com.android.server.uwb.data.UwbUciConstants.STATUS_CODE_DATA_TRANSFER_REPETITION_OK; import static com.google.common.truth.Truth.assertThat; import static com.google.uwb.support.fira.FiraParams.PARTICIPATION_AS_DEFINED_DEVICE_ROLE; import static com.google.uwb.support.fira.FiraParams.PROTOCOL_NAME; import static com.google.uwb.support.fira.FiraParams.RangeDataNtfConfigCapabilityFlag.HAS_RANGE_DATA_NTF_CONFIG_DISABLE; import static com.google.uwb.support.fira.FiraParams.RangeDataNtfConfigCapabilityFlag.HAS_RANGE_DATA_NTF_CONFIG_ENABLE; import static com.google.uwb.support.fira.FiraParams.SESSION_TYPE_RANGING; import static com.google.uwb.support.fira.FiraParams.STATUS_CODE_OK; import static com.google.uwb.support.radar.RadarParams.RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyByte; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.OnUidImportanceListener; import android.app.AlarmManager; import android.content.AttributionSource; import android.os.IBinder; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.test.TestLooper; import android.permission.flags.Flags; import android.util.Pair; import android.uwb.IUwbAdapter; import android.uwb.IUwbRangingCallbacks; import android.uwb.RangingChangeReason; import android.uwb.SessionHandle; import android.uwb.StateChangeReason; import android.uwb.UwbAddress; import android.uwb.UwbOemExtensionCallbackListener; import com.android.modules.utils.build.SdkLevel; import com.android.server.uwb.UwbSessionManager.UwbSession; import com.android.server.uwb.UwbSessionManager.WaitObj; import com.android.server.uwb.advertisement.UwbAdvertiseManager; import com.android.server.uwb.data.DtTagUpdateRangingRoundsStatus; import com.android.server.uwb.data.UwbDeviceInfoResponse; import com.android.server.uwb.data.UwbMulticastListUpdateStatus; import com.android.server.uwb.data.UwbRadarData; import com.android.server.uwb.data.UwbRangingData; import com.android.server.uwb.data.UwbUciConstants; import com.android.server.uwb.jni.NativeUwbManager; import com.android.server.uwb.multchip.UwbMultichipData; import com.android.server.uwb.params.TlvUtil; import com.google.uwb.support.aliro.AliroOpenRangingParams; import com.google.uwb.support.aliro.AliroParams; import com.google.uwb.support.aliro.AliroPulseShapeCombo; import com.google.uwb.support.aliro.AliroRangingStartedParams; import com.google.uwb.support.aliro.AliroSpecificationParams; import com.google.uwb.support.aliro.AliroStartRangingParams; import com.google.uwb.support.base.Params; import com.google.uwb.support.base.ProtocolVersion; import com.google.uwb.support.ccc.CccOpenRangingParams; import com.google.uwb.support.ccc.CccParams; import com.google.uwb.support.ccc.CccPulseShapeCombo; import com.google.uwb.support.ccc.CccRangingStartedParams; import com.google.uwb.support.ccc.CccSpecificationParams; import com.google.uwb.support.ccc.CccStartRangingParams; import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdate; import com.google.uwb.support.fira.FiraDataTransferPhaseConfig; import com.google.uwb.support.fira.FiraHybridSessionControleeConfig; import com.google.uwb.support.fira.FiraHybridSessionControllerConfig; import com.google.uwb.support.fira.FiraOpenSessionParams; import com.google.uwb.support.fira.FiraParams; import com.google.uwb.support.fira.FiraProtocolVersion; import com.google.uwb.support.fira.FiraRangingReconfigureParams; import com.google.uwb.support.fira.FiraSpecificationParams; import com.google.uwb.support.generic.GenericSpecificationParams; import com.google.uwb.support.radar.RadarOpenSessionParams; import com.google.uwb.support.radar.RadarParams; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeoutException; public class UwbSessionManagerTest { private static final String TEST_CHIP_ID = "testChipId"; private static final long MAX_FIRA_SESSION_NUM = 5; private static final long MAX_ALIRO_SESSION_NUM = 1; private static final long MAX_CCC_SESSION_NUM = 1; private static final int UID = 343453; private static final String PACKAGE_NAME = "com.uwb.test"; private static final int UID_2 = 67; private static final String PACKAGE_NAME_2 = "com.android.uwb.2"; private static final AttributionSource ATTRIBUTION_SOURCE = new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build(); private static final AttributionSource ATTRIBUTION_SOURCE_2 = new AttributionSource.Builder(UID_2).setPackageName(PACKAGE_NAME_2).build(); private static final SessionHandle SESSION_HANDLE = new SessionHandle(TEST_SESSION_ID, ATTRIBUTION_SOURCE, 1); private static final SessionHandle SESSION_HANDLE_2 = new SessionHandle(TEST_SESSION_ID_2, ATTRIBUTION_SOURCE_2, 2); private static final UwbAddress UWB_DEST_ADDRESS = UwbAddress.fromBytes(new byte[] {(byte) 0x03, (byte) 0x04 }); private static final UwbAddress UWB_DEST_ADDRESS_2 = UwbAddress.fromBytes(new byte[] {(byte) 0x05, (byte) 0x06 }); private static final UwbAddress UWB_DEST_ADDRESS_3 = UwbAddress.fromBytes(new byte[] {(byte) 0x07, (byte) 0x08 }); private static final int TEST_RANGING_INTERVAL_MS = 200; private static final short DATA_SEQUENCE_NUM = 0; private static final short DATA_SEQUENCE_NUM_1 = 2; private static final int DATA_TRANSMISSION_COUNT = 1; private static final int DATA_TRANSMISSION_COUNT_3 = 3; private static final int UWB_HUS_CONTROLLER_PHASE_LIST_SHORT_MAC_ADDRESS_SIZE = 11; private static final int UWB_HUS_CONTROLLER_PHASE_LIST_EXTENDED_MAC_ADDRESS_SIZE = 17; private static final int UWB_HUS_CONTROLEE_PHASE_LIST_SIZE = 5; private static final FiraProtocolVersion FIRA_VERSION_1_0 = new FiraProtocolVersion(1, 0); private static final FiraProtocolVersion FIRA_VERSION_1_1 = new FiraProtocolVersion(1, 1); private static final FiraProtocolVersion FIRA_VERSION_2_0 = new FiraProtocolVersion(2, 0); private static final FiraSpecificationParams FIRA_SPECIFICATION_PARAMS = new FiraSpecificationParams.Builder() .setMinPhyVersionSupported(FIRA_VERSION_1_0) .setMaxPhyVersionSupported(FIRA_VERSION_1_1) .setSupportedChannels(List.of(9)) .setRangeDataNtfConfigCapabilities( EnumSet.of( HAS_RANGE_DATA_NTF_CONFIG_DISABLE, HAS_RANGE_DATA_NTF_CONFIG_ENABLE)) .build(); private static final UwbDeviceInfoResponse UWB_DEVICE_INFO_RESPONSE_1_1 = new UwbDeviceInfoResponse( UwbUciConstants.STATUS_CODE_OK, /* UciVersion 1.1 = */ 0x1001, /* MacVersion 1.1 = */ 0x1001, /* PhyVersion 1.1 = */ 0x1001, /* UciTestVersion 1.1 = */ 0x1001, /* vendor_spec_info = */ new byte[]{0x0a, 0x0b, 0x0c, 0x0d}); private static final UwbDeviceInfoResponse UWB_DEVICE_INFO_RESPONSE_2_0 = new UwbDeviceInfoResponse( UwbUciConstants.STATUS_CODE_OK, /* UciVersion 2.0 = */ 0x0002, /* MacVersion 2.0 = */ 0x0002, /* PhyVersion 2.0 = */ 0x0002, /* UciTestVersion 2.0 = */ 0x0002, /* vendor_spec_info = */ new byte[]{0x0a, 0x0b, 0x0c, 0x0d}); private static final AliroOpenRangingParams ALIRO_OPEN_RANGING_PARAMS_DEFAULT = new AliroOpenRangingParams.Builder() .setProtocolVersion(AliroParams.PROTOCOL_VERSION_1_0) .setUwbConfig(AliroParams.UWB_CONFIG_0) .setPulseShapeCombo( new AliroPulseShapeCombo( AliroParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE, AliroParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE)) .setSessionId(1) .setRanMultiplier(4) .setChannel(AliroParams.UWB_CHANNEL_9) .setNumChapsPerSlot(AliroParams.CHAPS_PER_SLOT_3) .setNumResponderNodes(1) .setNumSlotsPerRound(AliroParams.SLOTS_PER_ROUND_6) .setSyncCodeIndex(1) .setHoppingConfigMode(AliroParams.HOPPING_CONFIG_MODE_NONE) .setHoppingSequence(AliroParams.HOPPING_SEQUENCE_DEFAULT) .build(); private static final CccOpenRangingParams CCC_OPEN_RANGING_PARAMS_DEFAULT = new CccOpenRangingParams.Builder() .setProtocolVersion(CccParams.PROTOCOL_VERSION_1_0) .setUwbConfig(CccParams.UWB_CONFIG_0) .setPulseShapeCombo( new CccPulseShapeCombo( CccParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE, CccParams.PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE)) .setSessionId(1) .setRanMultiplier(4) .setChannel(CccParams.UWB_CHANNEL_9) .setNumChapsPerSlot(CccParams.CHAPS_PER_SLOT_3) .setNumResponderNodes(1) .setNumSlotsPerRound(CccParams.SLOTS_PER_ROUND_6) .setSyncCodeIndex(1) .setHoppingConfigMode(CccParams.HOPPING_CONFIG_MODE_NONE) .setHoppingSequence(CccParams.HOPPING_SEQUENCE_DEFAULT) .build(); private FiraHybridSessionControllerConfig mHybridControllerParams = new FiraHybridSessionControllerConfig.Builder() .setNumberOfPhases(2) .setUpdateTime(new byte[8]) .setMacAddressMode((byte) 0) .addPhaseList( new FiraHybridSessionControllerConfig.FiraHybridSessionPhaseList( SESSION_HANDLE.getId(), (short) 0x01, (short) 0x34, (byte) PARTICIPATION_AS_DEFINED_DEVICE_ROLE, UWB_DEST_ADDRESS)) .addPhaseList( new FiraHybridSessionControllerConfig.FiraHybridSessionPhaseList( SESSION_HANDLE_2.getId(), (short) 0x37, (short) 0x64, (byte) PARTICIPATION_AS_DEFINED_DEVICE_ROLE, UWB_DEST_ADDRESS_2)) .build(); private FiraHybridSessionControleeConfig mHybridControleeParams = new FiraHybridSessionControleeConfig.Builder() .setNumberOfPhases(2) .addPhaseList( new FiraHybridSessionControleeConfig.FiraHybridSessionPhaseList( SESSION_HANDLE.getId(), (byte) PARTICIPATION_AS_DEFINED_DEVICE_ROLE)) .addPhaseList( new FiraHybridSessionControleeConfig.FiraHybridSessionPhaseList( SESSION_HANDLE_2.getId(), (byte) PARTICIPATION_AS_DEFINED_DEVICE_ROLE)) .build(); private static final long UWBS_TIMESTAMP = 2000000L; private static final int HANDLE_ID = 12; private static final int MAX_RX_DATA_PACKETS_TO_STORE = 10; private static final int PID = Process.myPid(); private static final int REFERENCE_SESSION_HANDLE = 10; private static final int SESSION_TOKEN = 1; @Mock private UwbConfigurationManager mUwbConfigurationManager; @Mock private NativeUwbManager mNativeUwbManager; @Mock private UwbMetrics mUwbMetrics; @Mock private UwbAdvertiseManager mUwbAdvertiseManager; @Mock private UwbSessionNotificationManager mUwbSessionNotificationManager; @Mock private UwbInjector mUwbInjector; @Mock private ExecutorService mExecutorService; @Mock private AlarmManager mAlarmManager; @Mock private ActivityManager mActivityManager; @Mock private UwbServiceCore mUwbServiceCore; @Mock private DeviceConfigFacade mDeviceConfigFacade; @Mock private AliroSpecificationParams mAliroSpecificationParams; @Mock private CccSpecificationParams mCccSpecificationParams; @Mock private UwbMultichipData mUwbMultichipData; private TestLooper mTestLooper = new TestLooper(); private UwbSessionManager mUwbSessionManager; @Captor private ArgumentCaptor mOnUidImportanceListenerArgumentCaptor; private GenericSpecificationParams.Builder mSpecificationParamsBuilder; @Before public void setup() throws ExecutionException, InterruptedException, TimeoutException { MockitoAnnotations.initMocks(this); when(mUwbInjector.isSystemApp(UID, PACKAGE_NAME)).thenReturn(true); when(mUwbInjector.isForegroundAppOrService(UID, PACKAGE_NAME)).thenReturn(true); when(mUwbInjector.getUwbServiceCore()).thenReturn(mUwbServiceCore); when(mUwbInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade); when(mUwbInjector.getMultichipData()).thenReturn(mUwbMultichipData); doAnswer(invocation -> { FutureTask t = invocation.getArgument(0); t.run(); return t.get(); }).when(mUwbInjector).runTaskOnSingleThreadExecutor(any(FutureTask.class), anyInt()); mSpecificationParamsBuilder = new GenericSpecificationParams.Builder() .setAliroSpecificationParams(mAliroSpecificationParams) .setCccSpecificationParams(mCccSpecificationParams) .setFiraSpecificationParams(FIRA_SPECIFICATION_PARAMS); when(mUwbServiceCore.getCachedSpecificationParams(any())).thenReturn( mSpecificationParamsBuilder.build()); when(mAliroSpecificationParams.getMaxRangingSessionNumber()).thenReturn( (int) MAX_ALIRO_SESSION_NUM); when(mCccSpecificationParams.getMaxRangingSessionNumber()).thenReturn( (int) MAX_CCC_SESSION_NUM); when(mUwbMultichipData.getDefaultChipId()).thenReturn("default"); when(mDeviceConfigFacade.isBackgroundRangingEnabled()).thenReturn(false); when(mDeviceConfigFacade.isRangingErrorStreakTimerEnabled()).thenReturn(true); // TODO: Don't use spy. mUwbSessionManager = spy(new UwbSessionManager( mUwbConfigurationManager, mNativeUwbManager, mUwbMetrics, mUwbAdvertiseManager, mUwbSessionNotificationManager, mUwbInjector, mAlarmManager, mActivityManager, mTestLooper.getLooper())); verify(mActivityManager).addOnUidImportanceListener( mOnUidImportanceListenerArgumentCaptor.capture(), anyInt()); } /** * Called after each test */ @After public void cleanup() { } @Test public void onDataReceived_extendedMacAddressFormat_owrAoA() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } @Test public void onDataReceived_unsupportedMacAddressLength_owrAoa() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_BAD_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession, never()).addReceivedDataInfo( isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics, never()).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } @Test public void onDataReceived_shortMacAddressFormat_owrAoa() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_SHORT_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } @Test public void onDataReceived_shortMacAddressFormat_dsTwr() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn( ROUND_USAGE_DS_TWR_NON_DEFERRED_MODE); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_SHORT_MAC_ADDRESS, DATA_PAYLOAD); verify(mUwbSessionNotificationManager).onDataReceived( isA(UwbSession.class), eq(PEER_EXTENDED_SHORT_UWB_ADDRESS), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); verify(mockUwbSession, never()).addReceivedDataInfo( isA(UwbSessionManager.ReceivedDataInfo.class)); } @Test public void onRangeDataNotificationReceivedWithValidUwbSession_twoWay() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); } @Test public void onRangeDataNotificationReceivedWithInvalidSession_twoWay() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); doReturn(null) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager, never()) .onRangingResult(any(), eq(uwbRangingData)); } // Test scenario for receiving Application payload data followed by a RANGE_DATA_NTF with an // OWR Aoa Measurement (such that the ExtendedMacAddress format is used for the remote device). @Test public void onRangeDataNotificationReceived_owrAoa_success_extendedMacAddress() throws RemoteException { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); UwbOemExtensionCallbackListener mUwbOemExtensionCallbackListener = mock(UwbOemExtensionCallbackListener.class); when(mUwbServiceCore.isOemExtensionCbRegistered()).thenReturn(true); when(mUwbServiceCore.getOemExtensionCallback()) .thenReturn(mUwbOemExtensionCallbackListener); when(mUwbOemExtensionCallbackListener.onCheckPointedTarget(any())).thenReturn(true); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)) .thenReturn(List.of(buildReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG))); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verify(mUwbSessionNotificationManager) .onDataReceived(eq(mockUwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_EXTENDED_MAC_ADDRESS_LONG); verify(mUwbMetrics).logDataToUpperLayer(eq(mockUwbSession), eq(1)); } // Test scenario for receiving Application payload data followed by a RANGE_DATA_NTF with an // OWR Aoa Measurement (such that the ShortMacAddress format is used for the remote device). @Test public void onRangeDataNotificationReceived_owrAoa_success_shortMacAddress() throws RemoteException { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); UwbOemExtensionCallbackListener mUwbOemExtensionCallbackListener = mock(UwbOemExtensionCallbackListener.class); when(mUwbServiceCore.isOemExtensionCbRegistered()).thenReturn(true); when(mUwbServiceCore.getOemExtensionCallback()) .thenReturn(mUwbOemExtensionCallbackListener); when(mUwbOemExtensionCallbackListener.onCheckPointedTarget(any())).thenReturn(true); // First call onDataReceived() to get the application payload data. This should always have // the MacAddress (in 8 Bytes), even for a Short MacAddress (MSB are zeroed out). mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_SHORT_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_OK); Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_SHORT_MAC_ADDRESS)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_SHORT_MAC_ADDRESS_LONG)) .thenReturn(List.of(buildReceivedDataInfo(PEER_EXTENDED_SHORT_MAC_ADDRESS_LONG))); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verify(mUwbSessionNotificationManager) .onDataReceived(eq(mockUwbSession), eq(PEER_SHORT_UWB_ADDRESS), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_SHORT_MAC_ADDRESS_LONG); verify(mUwbMetrics).logDataToUpperLayer(eq(mockUwbSession), eq(1)); } // Test scenario for receiving Application payload data followed by a RANGE_DATA_NTF with an // OWR Aoa Measurement, from Multiple advertiser devices in a UWB session. @Test public void onRangeDataNotificationReceived_owrAoa_success_multipleAdvertisers() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM_1, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS_2, DATA_PAYLOAD); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM_1, PEER_EXTENDED_MAC_ADDRESS_2, DATA_PAYLOAD); verify(mockUwbSession, times(4)).addReceivedDataInfo( isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics, times(4)).logDataRx( eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. UwbRangingData uwbRangingData1 = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, PEER_EXTENDED_MAC_ADDRESS, UwbUciConstants.STATUS_CODE_OK); UwbRangingData uwbRangingData2 = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, PEER_EXTENDED_MAC_ADDRESS_2, UwbUciConstants.STATUS_CODE_OK); Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(true); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS_2)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)) .thenReturn(List.of( buildReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM), buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM_1))); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_2_LONG)) .thenReturn(List.of( buildReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_2_LONG, DATA_SEQUENCE_NUM), buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_2_LONG, DATA_SEQUENCE_NUM_1))); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData1); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData2); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData1)); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData2)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData1.mRangingOwrAoaMeasure); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData2.mRangingOwrAoaMeasure); verify(mUwbSessionNotificationManager, times(2)) .onDataReceived(eq(mockUwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbSessionNotificationManager, times(2)) .onDataReceived(eq(mockUwbSession), eq(PEER_EXTENDED_UWB_ADDRESS_2), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_EXTENDED_MAC_ADDRESS_LONG); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_EXTENDED_MAC_ADDRESS_2_LONG); verify(mUwbMetrics, times(2)).logDataToUpperLayer(eq(mockUwbSession), eq(2)); } @Test public void onRangeDataNotificationReceived_owrAoa_CheckPointedTarget_Failed() throws RemoteException { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); UwbOemExtensionCallbackListener mUwbOemExtensionCallbackListener = mock(UwbOemExtensionCallbackListener.class); when(mUwbServiceCore.isOemExtensionCbRegistered()).thenReturn(true); when(mUwbServiceCore.getOemExtensionCallback()) .thenReturn(mUwbOemExtensionCallbackListener); when(mUwbOemExtensionCallbackListener.onCheckPointedTarget(any())).thenReturn(false); // First call onDataReceived() to get the application payload data. This should always have // the MacAddress (in 8 Bytes), even for a Short MacAddress (MSB are zeroed out). mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_SHORT_MAC_ADDRESS, DATA_PAYLOAD); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_OK); Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_SHORT_MAC_ADDRESS)).thenReturn(true); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verify(mUwbSessionNotificationManager, never()) .onDataReceived(eq(mockUwbSession), eq(PEER_SHORT_UWB_ADDRESS), isA(PersistableBundle.class), eq(DATA_PAYLOAD)); verify(mUwbAdvertiseManager, never()).removeAdvertiseTarget(PEER_SHORT_MAC_ADDRESS_LONG); } @Test public void onRangeDataNotificationReceived_owrAoa_missingUwbSession() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); // Setup the test scenario such that the UwbSession (from the RANGE_DATA_NTF) doesn't exist. doReturn(null) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verifyZeroInteractions(mUwbAdvertiseManager, mUwbSessionNotificationManager, mUwbMetrics); } @Test public void onRangeDataNotificationReceived_incorrectRangingMeasureType() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_UNDEFINED, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void onRangeDataNotificationReceived_owrAoa_incorrectRangingRoundUsage() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF (with an // incorrect RangingRoundUsage value). Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_DS_TWR_DEFERRED_MODE)); when(mockUwbSession.getParams()).thenReturn(firaParams); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void onRangeDataNotificationReceived_owrAoa_incorrectDeviceRole() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // First call onDataReceived() to get the application payload data. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_ADVERTISER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void onRangeDataNotificationReceived_owrAoa_receivedDataNotCalled() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // Skip call to mUwbSessionManager.onDataReceived(). This means there is no application // payload data, and so mUwbSessionNotificationManager.onDataReceived() shouldn't be called. Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)) .thenReturn(List.of()); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verifyZeroInteractions(mUwbSessionNotificationManager); verify(mUwbMetrics, never()).logDataToUpperLayer(eq(mockUwbSession), anyInt()); } @Test public void onRangeDataNotificationReceived_owrAoa_receivedDataDifferentMacAddress() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // onDataReceived() called for a different MacAddress, which should be equivalent to it // not being called. mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS_2, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)) .thenReturn(List.of()); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verifyZeroInteractions(mUwbSessionNotificationManager); verify(mUwbMetrics, never()).logDataToUpperLayer(eq(mockUwbSession), anyInt()); } @Test public void onRangeDataNotificationReceived_owrAoa_receivedDataDifferentUwbSession() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); UwbSession mockUwbSession2 = mock(UwbSession.class); when(mockUwbSession2.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession2.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession2) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID_2)); // onDataReceived() called for a different UwbSessionID, which should be equivalent to it // not being called. mUwbSessionManager.onDataReceived(TEST_SESSION_ID_2, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession2).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession2), eq(UwbUciConstants.STATUS_CODE_OK)); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. Setup such // that there is no ReceivedDataInfo returned for the UwbSession (to simulate the test // scenario). Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); when(mockUwbSession.getParams()).thenReturn(firaParams); when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(true); when(mockUwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)) .thenReturn(List.of()); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verifyZeroInteractions(mUwbSessionNotificationManager); verify(mUwbMetrics, never()).logDataToUpperLayer(eq(mockUwbSession), anyInt()); } @Test public void onRangeDataNotificationReceived_owrAoa_notPointedTarget() { UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getRangingRoundUsage()).thenReturn(ROUND_USAGE_OWR_AOA_MEASUREMENT); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class)); verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Setup isPointedTarget() to return false. when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(false); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager) .onRangingResult(eq(mockUwbSession), eq(uwbRangingData)); verify(mUwbAdvertiseManager, never()).removeAdvertiseTarget(isA(Long.class)); verifyZeroInteractions(mUwbSessionNotificationManager); } @Test public void onMulticastListUpdateNotificationReceivedWithValidSession() { UwbMulticastListUpdateStatus mockUwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getOperationType()) .thenReturn(UwbSessionManager.SESSION_RECONFIG_RANGING); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(anyInt()); mUwbSessionManager.onMulticastListUpdateNotificationReceived( mockUwbMulticastListUpdateStatus); verify(mockUwbSession, times(2)).getWaitObj(); verify(mockUwbSession) .setMulticastListUpdateStatus(eq(mockUwbMulticastListUpdateStatus)); } @Test public void onSessionStatusNotificationReceived_max_retry() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getSessionState()).thenReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE); mUwbSessionManager.onSessionStatusNotificationReceived( TEST_SESSION_ID, SESSION_TOKEN, UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.REASON_MAX_RANGING_ROUND_RETRY_COUNT_REACHED); verify(mockUwbSession, times(2)).getWaitObj(); verify(mockUwbSession).setSessionState(eq(UwbUciConstants.UWB_SESSION_STATE_IDLE)); verify(mUwbSessionNotificationManager).onRangingStoppedWithUciReasonCode( eq(mockUwbSession), eq(UwbUciConstants.REASON_MAX_RANGING_ROUND_RETRY_COUNT_REACHED)); } @Test public void onSessionStatusNotificationReceived_session_mgmt_cmds() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getSessionState()).thenReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE); mUwbSessionManager.onSessionStatusNotificationReceived( TEST_SESSION_ID, SESSION_TOKEN, UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS); verify(mockUwbSession, times(2)).getWaitObj(); verify(mockUwbSession).setSessionState(eq(UwbUciConstants.UWB_SESSION_STATE_IDLE)); verify(mUwbSessionNotificationManager, never()).onRangingStoppedWithUciReasonCode( any(), anyInt()); } @Test public void initSession_ExistedSession() throws RemoteException { IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); doReturn(true).when(mUwbSessionManager).isExistedSession(anyInt()); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mock(SessionHandle.class), TEST_SESSION_ID, TEST_SESSION_TYPE, "any", mock(Params.class), mockRangingCallbacks, TEST_CHIP_ID); verify(mockRangingCallbacks).onRangingOpenFailed( any(), eq(RangingChangeReason.BAD_PARAMETERS), any()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void initFiraSession_maxSessionsExceeded() throws RemoteException { doReturn(MAX_FIRA_SESSION_NUM).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mock(SessionHandle.class), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mock(Params.class), mockRangingCallbacks, TEST_CHIP_ID); verify(mockRangingCallbacks).onRangingOpenFailed(any(), eq(RangingChangeReason.MAX_SESSIONS_REACHED), any()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void initAliroSession_maxSessionsExceeded() throws RemoteException { doReturn(MAX_ALIRO_SESSION_NUM).when(mUwbSessionManager).getAliroSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mock(SessionHandle.class), TEST_SESSION_ID, TEST_SESSION_TYPE, AliroParams.PROTOCOL_NAME, mock(Params.class), mockRangingCallbacks, TEST_CHIP_ID); verify(mockRangingCallbacks).onRangingOpenFailed(any(), eq(RangingChangeReason.MAX_SESSIONS_REACHED), any()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void initCccSession_maxSessionsExceeded() throws RemoteException { doReturn(MAX_CCC_SESSION_NUM).when(mUwbSessionManager).getCccSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mock(SessionHandle.class), TEST_SESSION_ID, TEST_SESSION_TYPE, CccParams.PROTOCOL_NAME, mock(Params.class), mockRangingCallbacks, TEST_CHIP_ID); verify(mockRangingCallbacks).onRangingOpenFailed(any(), eq(RangingChangeReason.MAX_SESSIONS_REACHED), any()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void initSession_UwbSession_RemoteException() throws RemoteException { doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getAliroSessionCount(); doReturn(0L).when(mUwbSessionManager).getCccSessionCount(); doReturn(0L).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); Params mockParams = mock(FiraParams.class); IBinder mockBinder = mock(IBinder.class); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doThrow(new RemoteException()).when(mockBinder).linkToDeath(any(), anyInt()); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID); verify(uwbSession).binderDied(); verify(mockRangingCallbacks).onRangingOpenFailed(any(), anyInt(), any()); verify(mockBinder, atLeast(1)).unlinkToDeath(any(), anyInt()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void initSession_success() throws RemoteException { doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getAliroSessionCount(); doReturn(0L).when(mUwbSessionManager).getCccSessionCount(); doReturn(0L).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); Params mockParams = mock(FiraParams.class); IBinder mockBinder = mock(IBinder.class); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID); verify(uwbSession, never()).binderDied(); verify(mockRangingCallbacks, never()).onRangingOpenFailed(any(), anyInt(), any()); verify(mockBinder, never()).unlinkToDeath(any(), anyInt()); assertThat(mUwbSessionManager.getUwbSession(TEST_SESSION_ID)).isEqualTo(uwbSession); assertThat(mTestLooper.nextMessage().what).isEqualTo(1); // SESSION_OPEN_RANGING } @Test public void initSessionMaxSessions_lowestPrioritySessionReplaced() throws RemoteException { doReturn(false).when(mUwbInjector).isSystemApp(UID, PACKAGE_NAME); doReturn(true).when(mUwbInjector).isSystemApp(UID_2, PACKAGE_NAME_2); doReturn(1L).when(mUwbSessionManager).getMaxFiraSessionsNumber(TEST_CHIP_ID); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); Params mockParams = mock(FiraParams.class); IBinder mockBinder = mock(IBinder.class); when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mNativeUwbManager.deInitSession(anyInt(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); // Init session for 3rd party FG app UwbSession lowPrioUwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, SESSION_HANDLE, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(lowPrioUwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(lowPrioUwbSession).getSessionState(); doReturn(mock(WaitObj.class)).when(lowPrioUwbSession).getWaitObj(); doReturn(mockBinder).when(lowPrioUwbSession).getBinder(); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, SESSION_HANDLE, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(mUwbSessionManager.getUwbSession(TEST_SESSION_ID)).isEqualTo(lowPrioUwbSession); mTestLooper.dispatchNext(); // Init session for system app UwbSession highPrioUwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE_2, SESSION_HANDLE_2, TEST_SESSION_ID_2, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(highPrioUwbSession).getBinder(); doReturn(mock(WaitObj.class)).when(highPrioUwbSession).getWaitObj(); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(highPrioUwbSession).getSessionState(); doReturn(highPrioUwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE_2, SESSION_HANDLE_2, TEST_SESSION_ID_2, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mNativeUwbManager).initSession(TEST_SESSION_ID, TEST_SESSION_TYPE, TEST_CHIP_ID); verify(mNativeUwbManager).deInitSession(TEST_SESSION_ID, TEST_CHIP_ID); verify(mNativeUwbManager).initSession(TEST_SESSION_ID_2, TEST_SESSION_TYPE, TEST_CHIP_ID); verify(mockRangingCallbacks, never()).onRangingOpenFailed(any(), anyInt(), any()); verify(mUwbSessionNotificationManager).onRangingOpened(lowPrioUwbSession); verify(mUwbSessionNotificationManager).onRangingClosed(lowPrioUwbSession, UwbUciConstants.STATUS_CODE_ERROR_MAX_SESSIONS_EXCEEDED); verify(mUwbSessionNotificationManager).onRangingOpened(highPrioUwbSession); assertThat(mUwbSessionManager.getUwbSession(TEST_SESSION_ID)).isNull(); assertThat(mUwbSessionManager.getUwbSession(TEST_SESSION_ID_2)).isEqualTo( highPrioUwbSession); } @Test public void testNeedsAppConfigUpdate_setAppConfigCalledOnStartRanging() throws RemoteException { UwbSession mockUwbSession = mock(UwbSession.class); doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mockUwbSession).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); doReturn(PROTOCOL_NAME).when(mockUwbSession).getProtocolName(); doReturn(mock(WaitObj.class)).when(mockUwbSession).getWaitObj(); when(mockUwbSession.getNeedsAppConfigUpdate()).thenReturn(true); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); mTestLooper.dispatchAll(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_1_1)); } @Test public void testCreateUwbSession_correctSessionPrioritiesSet() throws RemoteException { IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); FiraOpenSessionParams mockFiraOpenSessionParams = mock(FiraOpenSessionParams.class); Params mockCccParams = mock(CccParams.class); Params mockAliroParams = mock(AliroParams.class); FiraOpenSessionParams.Builder mockFiraBuilder = mock(FiraOpenSessionParams.Builder.class); when(mockFiraOpenSessionParams.toBuilder()).thenReturn(mockFiraBuilder); when(mockFiraBuilder.setSessionPriority(anyInt())).thenReturn(mockFiraBuilder); when(mockFiraBuilder.build()).thenReturn(mockFiraOpenSessionParams); when(mockFiraOpenSessionParams.getSessionPriority()).thenReturn( UwbSession.DEFAULT_SESSION_PRIORITY); // System session String systemPackageName = "com.google.uwb"; when(mUwbInjector.isSystemApp(UID, systemPackageName)).thenReturn(true); AttributionSource attributionSourceSystemApp = new AttributionSource.Builder(UID).setPackageName(systemPackageName).build(); UwbSession systemUwbSession = mUwbSessionManager.new UwbSession(attributionSourceSystemApp, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockFiraOpenSessionParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(systemUwbSession.getStackSessionPriority()).isEqualTo( UwbSession.SYSTEM_APP_SESSION_PRIORITY); verify(mockFiraBuilder).setSessionPriority(UwbSession.SYSTEM_APP_SESSION_PRIORITY); // CCC session UwbSession cccUwbSession = mUwbSessionManager.new UwbSession(attributionSourceSystemApp, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, CccParams.PROTOCOL_NAME, mockCccParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(cccUwbSession.getStackSessionPriority()).isEqualTo( UwbSession.CCC_SESSION_PRIORITY); // ALIRO session UwbSession aliroUwbSession = mUwbSessionManager.new UwbSession(attributionSourceSystemApp, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, AliroParams.PROTOCOL_NAME, mockAliroParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(aliroUwbSession.getStackSessionPriority()).isEqualTo( UwbSession.ALIRO_SESSION_PRIORITY); // 3rd party foreground session String nonSystemPackageName = "com.something.app"; when(mUwbInjector.isForegroundAppOrService(UID, nonSystemPackageName)) .thenReturn(true); AttributionSource attributionSourceNonSystemApp = new AttributionSource.Builder(UID).setPackageName(nonSystemPackageName).build(); UwbSession nonSystemFgUwbSession = mUwbSessionManager.new UwbSession(attributionSourceNonSystemApp, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockFiraOpenSessionParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(nonSystemFgUwbSession.getStackSessionPriority()).isEqualTo( UwbSession.FG_SESSION_PRIORITY); verify(mockFiraBuilder).setSessionPriority(UwbSession.FG_SESSION_PRIORITY); // 3rd party background session when(mUwbInjector.isForegroundAppOrService(UID, nonSystemPackageName)) .thenReturn(false); UwbSession nonSystemBgUwbSession = mUwbSessionManager.new UwbSession(attributionSourceNonSystemApp, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockFiraOpenSessionParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(nonSystemBgUwbSession.getStackSessionPriority()).isEqualTo( UwbSession.BG_SESSION_PRIORITY); verify(mockFiraBuilder).setSessionPriority(UwbSession.BG_SESSION_PRIORITY); } @Test public void initSession_controleeList() throws RemoteException { doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getCccSessionCount(); doReturn(0L).when(mUwbSessionManager).getAliroSessionCount(); doReturn(0L).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); FiraOpenSessionParams mockParams = mock(FiraOpenSessionParams.class); FiraOpenSessionParams.Builder mockBuilder = mock(FiraOpenSessionParams.Builder.class); IBinder mockBinder = mock(IBinder.class); when(mockParams.getDestAddressList()) .thenReturn(Collections.singletonList(UWB_DEST_ADDRESS)); when(mockParams.toBuilder()).thenReturn(mockBuilder); when(mockBuilder.setSessionPriority(anyInt())).thenReturn(mockBuilder); when(mockBuilder.build()).thenReturn(mockParams); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, mockParams, mockRangingCallbacks, TEST_CHIP_ID); assertThat(uwbSession.getControleeList().size() == 1 && uwbSession.getControleeList().get(0).getUwbAddress().equals(UWB_DEST_ADDRESS)) .isTrue(); assertThat(uwbSession.getControlee(UWB_DEST_ADDRESS) .getUwbAddress().equals(UWB_DEST_ADDRESS)).isTrue(); verify(uwbSession, never()).binderDied(); verify(mockRangingCallbacks, never()).onRangingOpenFailed(any(), anyInt(), any()); verify(mockBinder, never()).unlinkToDeath(any(), anyInt()); assertThat(mUwbSessionManager.getUwbSession(TEST_SESSION_ID)).isEqualTo(uwbSession); assertThat(mTestLooper.nextMessage().what).isEqualTo(1); // SESSION_OPEN_RANGING } @Test public void startRanging_notExistedSession() { doReturn(false).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void startRanging_currentSessionStateIdle() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); UwbSession uwbSession = mock(UwbSession.class); when(uwbSession.getProtocolName()).thenReturn(FiraParams.PROTOCOL_NAME); doReturn(uwbSession).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); assertThat(mTestLooper.nextMessage().what).isEqualTo(2); // SESSION_START_RANGING } @Test public void startRanging_currentCccSessionStateActive() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); UwbSession mockUwbSession = mock(UwbSession.class); doReturn(mockUwbSession).when(mUwbSessionManager).getUwbSession(anyInt()); when(mockUwbSession.getProtocolName()).thenReturn(CccParams.PROTOCOL_NAME); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); verify(mUwbSessionNotificationManager).onRangingStartFailed( any(), eq(UwbUciConstants.STATUS_CODE_REJECTED)); } @Test public void startRanging_currentAliroSessionStateActive() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); UwbSession mockUwbSession = mock(UwbSession.class); doReturn(mockUwbSession).when(mUwbSessionManager).getUwbSession(anyInt()); when(mockUwbSession.getProtocolName()).thenReturn(AliroParams.PROTOCOL_NAME); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); verify(mUwbSessionNotificationManager).onRangingStartFailed( any(), eq(UwbUciConstants.STATUS_CODE_REJECTED)); } @Test public void startRanging_currentSessionStateInvalid() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_ERROR) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.startRanging(mock(SessionHandle.class), mock(Params.class)); verify(mUwbSessionNotificationManager) .onRangingStartFailed(any(), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void stopRanging_notExistedSession() { doReturn(false).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.stopRanging(mock(SessionHandle.class)); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void stopRanging_currentSessionStateActive() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.stopRanging(mock(SessionHandle.class)); assertThat(mTestLooper.nextMessage().what).isEqualTo(3); // SESSION_STOP_RANGING } @Test public void stopRanging_currentSessionStateActive_owrAoa() { UwbSession mockUwbSession = mock(UwbSession.class); doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mockUwbSession).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(PROTOCOL_NAME).when(mockUwbSession).getProtocolName(); doReturn(0).when(mockUwbSession).getCurrentFiraRangingIntervalMs(); // Setup the UwbSession to have the peer device's MacAddress stored (which happens when // a valid RANGE_DATA_NTF with an OWR AoA Measurement is received). doReturn(Set.of(PEER_EXTENDED_MAC_ADDRESS_LONG)).when(mockUwbSession) .getRemoteMacAddressList(); mUwbSessionManager.stopRanging(mock(SessionHandle.class)); mTestLooper.dispatchNext(); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_EXTENDED_MAC_ADDRESS_LONG); } @Test public void stopRanging_currentSessionStateIdle() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.stopRanging(mock(SessionHandle.class)); verify(mUwbSessionNotificationManager).onRangingStopped(any(), eq(UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS)); } @Test public void stopRanging_currentSessionStateInvalid() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(mock(UwbSession.class)).when(mUwbSessionManager).getUwbSession(anyInt()); doReturn(UwbUciConstants.UWB_SESSION_STATE_ERROR) .when(mUwbSessionManager).getCurrentSessionState(anyInt()); mUwbSessionManager.stopRanging(mock(SessionHandle.class)); verify(mUwbSessionNotificationManager).onRangingStopFailed(any(), eq(UwbUciConstants.STATUS_CODE_REJECTED)); } @Test public void getUwbSession_success() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); UwbSession actualUwbSession = mUwbSessionManager.getUwbSession(TEST_SESSION_ID); assertThat(actualUwbSession).isEqualTo(mockUwbSession); } @Test public void getUwbSession_failed() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); UwbSession actualUwbSession = mUwbSessionManager.getUwbSession(TEST_SESSION_ID - 1); assertThat(actualUwbSession).isNull(); } @Test public void getSessionId_success() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); SessionHandle mockSessionHandle = mock(SessionHandle.class); mUwbSessionManager.mSessionTable.put(mockSessionHandle, mockUwbSession); when(mockUwbSession.getSessionHandle()).thenReturn(mockSessionHandle); int actualSessionId = mUwbSessionManager.getSessionId(mockSessionHandle); assertThat(actualSessionId).isEqualTo(TEST_SESSION_ID); } @Test public void getSessionId_failed() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); SessionHandle mockSessionHandle = mock(SessionHandle.class); mUwbSessionManager.mSessionTable.put(mockSessionHandle, mockUwbSession); when(mockUwbSession.getSessionHandle()).thenReturn(mockSessionHandle); Integer actualSessionId = mUwbSessionManager.getSessionId(mock(SessionHandle.class)); assertThat(actualSessionId).isNull(); } @Test public void isExistedSession_sessionHandle_success() { doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); boolean result = mUwbSessionManager.isExistedSession(mock(SessionHandle.class)); assertThat(result).isTrue(); } @Test public void iexExistedSession_sessionHandle_failed() { doReturn(null).when(mUwbSessionManager).getSessionId(any()); boolean result = mUwbSessionManager.isExistedSession(mock(SessionHandle.class)); assertThat(result).isFalse(); } @Test public void isExistedSession_sessionId_success() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); boolean result = mUwbSessionManager.isExistedSession(TEST_SESSION_ID); assertThat(result).isTrue(); } @Test public void iexExistedSession_sessionId_failed() { boolean result = mUwbSessionManager.isExistedSession(TEST_SESSION_ID); assertThat(result).isFalse(); } @Test public void stopAllRanging() { UwbSession mockUwbSession1 = mock(UwbSession.class); when(mockUwbSession1.getSessionId()).thenReturn(TEST_SESSION_ID); when(mockUwbSession1.getChipId()).thenReturn(TEST_CHIP_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession1); UwbSession mockUwbSession2 = mock(UwbSession.class); when(mockUwbSession2.getSessionId()).thenReturn(TEST_SESSION_ID + 100); when(mockUwbSession2.getChipId()).thenReturn(TEST_CHIP_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession2); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID + 100), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.stopAllRanging(); verify(mNativeUwbManager, times(2)) .stopRanging(anyInt(), anyString()); verify(mockUwbSession1, never()).setSessionState(anyInt()); verify(mockUwbSession2).setSessionState(eq(UwbUciConstants.UWB_SESSION_STATE_IDLE)); } @Test public void setCurrentSessionState() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); mUwbSessionManager.setCurrentSessionState( TEST_SESSION_ID, UwbUciConstants.UWB_SESSION_STATE_ACTIVE); verify(mockUwbSession).setSessionState(eq(UwbUciConstants.UWB_SESSION_STATE_ACTIVE)); } @Test public void getCurrentSessionState_nullSession() { int actualStatus = mUwbSessionManager.getCurrentSessionState(TEST_SESSION_ID); assertThat(actualStatus).isEqualTo(UwbUciConstants.UWB_SESSION_STATE_ERROR); } @Test public void getCurrentSessionState_success() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); when(mockUwbSession.getSessionState()).thenReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); int actualStatus = mUwbSessionManager.getCurrentSessionState(TEST_SESSION_ID); assertThat(actualStatus).isEqualTo(UwbUciConstants.UWB_SESSION_STATE_ACTIVE); } @Test public void getSessionIdSet() { UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getSessionId()).thenReturn(TEST_SESSION_ID); mUwbSessionManager.mSessionTable.put(mock(SessionHandle.class), mockUwbSession); Set actualSessionIds = mUwbSessionManager.getSessionIdSet(); assertThat(actualSessionIds).hasSize(1); assertThat(actualSessionIds.contains(TEST_SESSION_ID)).isTrue(); } @Test public void reconfigure_notExistedSession() { doReturn(false).when(mUwbSessionManager).isExistedSession(any()); int actualStatus = mUwbSessionManager.reconfigure( mock(SessionHandle.class), mock(Params.class)); assertThat(actualStatus).isEqualTo(UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST); } private UwbSession setUpUwbSessionForExecution(AttributionSource attributionSource) { return setUpUwbSessionForExecution(attributionSource, setupFiraParams()); } private UwbSession setUpUwbSessionForExecution(AttributionSource attributionSource, Params params) { // setup message doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); IBinder mockBinder = mock(IBinder.class); byte sessionType = TEST_SESSION_TYPE; if (params.getProtocolName().equals(RadarParams.PROTOCOL_NAME) && params instanceof RadarOpenSessionParams) { sessionType = (byte) RadarParams.SESSION_TYPE_RADAR; } UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(attributionSource, mockSessionHandle, TEST_SESSION_ID, sessionType, params.getProtocolName(), params, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doReturn(mock(WaitObj.class)).when(uwbSession).getWaitObj(); return uwbSession; } private UwbAddress setUpControlee(UwbSessionManager.UwbSession session, int macAddressingMode) { UwbAddress uwbAddress = (macAddressingMode == MAC_ADDRESSING_MODE_SHORT) ? PEER_SHORT_UWB_ADDRESS : PEER_EXTENDED_UWB_ADDRESS; session.mMulticastRangingErrorStreakTimerListeners = spy(new ConcurrentHashMap<>()); session.mControlees = spy(new ConcurrentHashMap<>()); session.addControlee(uwbAddress); return uwbAddress; } private void startRanging(UwbSession session) { doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(session).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging( session.getSessionHandle(), session.getParams()); mTestLooper.dispatchAll(); } private Params setupFiraParams() { return setupFiraParams(FIRA_VERSION_2_0); } private Params setupFiraParams(FiraProtocolVersion firaProtocolVersion) { return setupFiraParams( FiraParams.RANGING_DEVICE_ROLE_INITIATOR, /* rangingRoundusageOptional = */ Optional.empty(), firaProtocolVersion); } private Params setupFiraParams( int deviceRole, Optional rangingRoundUsageOptional) { return setupFiraParams(deviceRole, rangingRoundUsageOptional, FIRA_VERSION_1_0); } private Params setupFiraParams( int deviceRole, Optional rangingRoundUsageOptional, FiraProtocolVersion firaProtocolVersion) { FiraOpenSessionParams.Builder paramsBuilder = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(firaProtocolVersion) .setSessionId(10) .setSessionType(SESSION_TYPE_RANGING) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(deviceRole) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS); if (rangingRoundUsageOptional.isPresent()) { paramsBuilder.setRangingRoundUsage(rangingRoundUsageOptional.get()); } return paramsBuilder.build(); } // setup uwbsession with give sessionType private UwbSession setUpUwbSessionForExecutionWithSessionType(byte sessionType, Params params) { doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getFiraSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); IBinder mockBinder = mock(IBinder.class); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, sessionType, params.getProtocolName(), params, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doReturn(mock(WaitObj.class)).when(uwbSession).getWaitObj(); return uwbSession; } private Params setupRadarParams() { return new RadarOpenSessionParams.Builder() .setSessionId(22) .setBurstPeriod(100) .setSweepPeriod(40) .setSweepsPerBurst(16) .setSamplesPerSweep(128) .setChannelNumber(FiraParams.UWB_CHANNEL_5) .setSweepOffset(-1) .setRframeConfig(FiraParams.RFRAME_CONFIG_SP3) .setPreambleDuration(RadarParams.PREAMBLE_DURATION_T16384_SYMBOLS) .setPreambleCodeIndex(90) .setSessionPriority(99) .setBitsPerSample(RadarParams.BITS_PER_SAMPLES_32) .setPrfMode(FiraParams.PRF_MODE_HPRF) .setNumberOfBursts(1000) .setRadarDataType(RadarParams.RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES) .build(); } private UwbSession setUpCccUwbSessionForExecution(Params params) throws RemoteException { // Setup message doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getCccSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); IBinder mockBinder = mock(IBinder.class); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, CccParams.PROTOCOL_NAME, params, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doReturn(mock(WaitObj.class)).when(uwbSession).getWaitObj(); return uwbSession; } private UwbSession setUpAliroUwbSessionForExecution(Params params) throws RemoteException { // Setup message doReturn(0).when(mUwbSessionManager).getSessionCount(); doReturn(0L).when(mUwbSessionManager).getAliroSessionCount(); doReturn(false).when(mUwbSessionManager).isExistedSession(anyInt()); IUwbRangingCallbacks mockRangingCallbacks = mock(IUwbRangingCallbacks.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); IBinder mockBinder = mock(IBinder.class); UwbSession uwbSession = spy( mUwbSessionManager.new UwbSession(ATTRIBUTION_SOURCE, mockSessionHandle, TEST_SESSION_ID, TEST_SESSION_TYPE, AliroParams.PROTOCOL_NAME, params, mockRangingCallbacks, TEST_CHIP_ID)); doReturn(mockBinder).when(uwbSession).getBinder(); doReturn(uwbSession).when(mUwbSessionManager).createUwbSession(any(), any(), anyInt(), anyByte(), anyString(), any(), any(), anyString()); doReturn(mock(WaitObj.class)).when(uwbSession).getWaitObj(); return uwbSession; } // Test SESSION_INIT for a FiRa ranging session on a UWBS controller (UCI ver 1.1+). @Test public void openRanging_success_fira_uwbs_v1_1() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); do_openRanging_success_absoluteInitiationTimeIsNotComputed( FiraParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_1_1, FIRA_VERSION_1_1); } // Test SESSION_INIT for a CCC ranging session on a UWBS controller (UCI ver 1.1+). @Test public void openRanging_success_ccc_uwbs_v1_1() throws Exception { UwbSession uwbSession = setUpCccUwbSessionForExecution(CCC_OPEN_RANGING_PARAMS_DEFAULT); do_openRanging_success_absoluteInitiationTimeIsNotComputed( CccParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_1_1, FIRA_VERSION_1_1); } // Test SESSION_INIT for an ALIRO ranging session on a UWBS controller (UCI ver 1.1+). @Test public void openRanging_success_aliro_uwbs_v1_1() throws Exception { UwbSession uwbSession = setUpAliroUwbSessionForExecution(ALIRO_OPEN_RANGING_PARAMS_DEFAULT); do_openRanging_success_absoluteInitiationTimeIsNotComputed( AliroParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_1_1, FIRA_VERSION_1_1); } // Test SESSION_INIT for a CCC ranging session on a UWBS controller (UCI ver 2.0+). Currently, // we don't expect this to set the {@code CccOpenRangingParams.mAbsoluteInitiationTimeUs} // (at SESSION_INIT time), or, result in the UWBS_TIMESTAMP being fetched from the UWBS. @Test public void openRanging_success_ccc_uwbs_v2_0_absoluteInitiationTimeComputationIsDisabled() throws Exception { // Setup the flag to "false" (which is also the default value), so that absolute // UWB initiation time computation is disabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(false); CccOpenRangingParams params = CCC_OPEN_RANGING_PARAMS_DEFAULT.toBuilder() .setInitiationTimeMs(1000) .build(); UwbSession uwbSession = setUpCccUwbSessionForExecution(params); do_openRanging_success_absoluteInitiationTimeIsNotComputed( CccParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_2_0, FIRA_VERSION_2_0); } // Test SESSION_INIT for a ALIRO ranging session on a UWBS controller (UCI ver 2.0+). Currently, // we don't expect this to set the {@code AliroOpenRangingParams.mAbsoluteInitiationTimeUs} // (at SESSION_INIT time), or, result in the UWBS_TIMESTAMP being fetched from the UWBS. @Test public void openRanging_success_aliro_uwbs_v2_0_absoluteInitiationTimeComputationIsDisabled() throws Exception { // Setup the flag to "false" (which is also the default value), so that absolute // UWB initiation time computation is disabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(false); AliroOpenRangingParams params = ALIRO_OPEN_RANGING_PARAMS_DEFAULT.toBuilder() .setInitiationTimeMs(1000) .build(); UwbSession uwbSession = setUpAliroUwbSessionForExecution(params); do_openRanging_success_absoluteInitiationTimeIsNotComputed( AliroParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_2_0, FIRA_VERSION_2_0); } // Test SESSION_INIT for a CCC ranging session on a UWBS controller (UCI ver 2.0+). Currently, // we don't expect this to set the {@code CccOpenRangingParams.mAbsoluteInitiationTimeUs} // (at SESSION_INIT time), or, result in the UWBS_TIMESTAMP being fetched from the UWBS. @Test public void openRanging_success_ccc_uwbs_v2_0_absoluteInitiationTimeComputationIsEnabled() throws Exception { // Setup the flag to "true", so that absolute UWB initiation time computation // is enabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = setUpCccUwbSessionForExecution(CCC_OPEN_RANGING_PARAMS_DEFAULT); do_openRanging_success_absoluteInitiationTimeIsNotComputed( CccParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_2_0, FIRA_VERSION_2_0); } // Test SESSION_INIT for a ALIRO ranging session on a UWBS controller (UCI ver 2.0+). Currently, // we don't expect this to set the {@code AliroOpenRangingParams.mAbsoluteInitiationTimeUs} // (at SESSION_INIT time), or, result in the UWBS_TIMESTAMP being fetched from the UWBS. @Test public void openRanging_success_aliro_uwbs_v2_0_absoluteInitiationTimeComputationIsEnabled() throws Exception { // Setup the flag to "true", so that absolute UWB initiation time computation // is enabled for a ALIRO ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = setUpAliroUwbSessionForExecution(ALIRO_OPEN_RANGING_PARAMS_DEFAULT); do_openRanging_success_absoluteInitiationTimeIsNotComputed( AliroParams.PROTOCOL_NAME, uwbSession, UWB_DEVICE_INFO_RESPONSE_2_0, FIRA_VERSION_2_0); } private void do_openRanging_success_absoluteInitiationTimeIsNotComputed( String protocolName, UwbSession uwbSession, UwbDeviceInfoResponse uwbDeviceInfoResponse, ProtocolVersion uwbsFiraVersion) throws Exception { // Setup the UWBS to return Fira UCI version as 2.0. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( uwbDeviceInfoResponse); // Stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, protocolName, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); // Verifications related to Open Ranging. verify(mNativeUwbManager).initSession(eq(TEST_SESSION_ID), anyByte(), eq(TEST_CHIP_ID)); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), any(), eq(TEST_CHIP_ID), eq(uwbsFiraVersion)); verify(mUwbSessionNotificationManager).onRangingOpened(eq(uwbSession)); verify(mUwbMetrics).logRangingInitEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Verify that queryUwbsTimestampMicros() is not called, as the "params" doesn't have the // "mInitiationTime" field set. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); } @Test public void openRanging_success_Fira_2_0_absoluteInitiationTimeIsComputed() throws Exception { // Set the InitationTime in the FiraOpenSessionParams. FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_2_0)) .setInitiationTime(100L) .build(); UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE, firaParams); do_openRanging_success_uwbs_2_0_absoluteInitiationTimeIsComputed( FiraParams.PROTOCOL_NAME, uwbSession); } @Test public void openRanging_success_Ccc_absoluteInitiationTimeIsComputed() throws Exception { // Setup the flag to "true", so that absolute UWB initiation time computation // is enabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); CccOpenRangingParams params = CCC_OPEN_RANGING_PARAMS_DEFAULT.toBuilder() .setInitiationTimeMs(1000) .build(); UwbSession uwbSession = setUpCccUwbSessionForExecution(params); do_openRanging_success_uwbs_2_0_absoluteInitiationTimeIsComputed( CccParams.PROTOCOL_NAME, uwbSession); } @Test public void openRanging_success_Aliro_absoluteInitiationTimeIsComputed() throws Exception { // Setup the flag to "true", so that absolute UWB initiation time computation // is enabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); AliroOpenRangingParams params = ALIRO_OPEN_RANGING_PARAMS_DEFAULT.toBuilder() .setInitiationTimeMs(1000) .build(); UwbSession uwbSession = setUpAliroUwbSessionForExecution(params); do_openRanging_success_uwbs_2_0_absoluteInitiationTimeIsComputed( AliroParams.PROTOCOL_NAME, uwbSession); } // Test SESSION_INIT for a Fira ranging session on a UWBS controller (UCI ver 2.0+). We expect // this to set the {@code FiraOpenSessionParams.mAbsoluteInitiationTime} (at SESSION_INIT time), // after fetching the UWBS_TIMESTAMP from the UWBS. private void do_openRanging_success_uwbs_2_0_absoluteInitiationTimeIsComputed( String protocolName, UwbSession uwbSession) throws Exception { // Setup the UWBS to return Fira UCI version as 2.0. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( UWB_DEVICE_INFO_RESPONSE_2_0); // Stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, protocolName, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); // Verifications related to CCC Open Ranging - we expect queryUwbsTimestampMicros() // to be called. verify(mNativeUwbManager).initSession(eq(TEST_SESSION_ID), anyByte(), eq(TEST_CHIP_ID)); verify(mUwbServiceCore).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), any(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_2_0)); verify(mUwbSessionNotificationManager).onRangingOpened(eq(uwbSession)); verify(mUwbMetrics).logRangingInitEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } @Test public void openRanging_timeout() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); // stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenThrow(new IllegalStateException()); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mUwbMetrics).logRangingInitEvent(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager) .onRangingOpenFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mNativeUwbManager).deInitSession(eq(TEST_SESSION_ID), eq(TEST_CHIP_ID)); } @Test public void openRanging_nativeInitSessionFailed() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); // stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mUwbMetrics).logRangingInitEvent(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager) .onRangingOpenFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mNativeUwbManager).deInitSession(eq(TEST_SESSION_ID), eq(TEST_CHIP_ID)); } @Test public void openRanging_setAppConfigurationFailed() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); // stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mUwbMetrics).logRangingInitEvent(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager) .onRangingOpenFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mNativeUwbManager).deInitSession(eq(TEST_SESSION_ID), eq(TEST_CHIP_ID)); } @Test public void openRanging_wrongInitState() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); // stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_ERROR, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mUwbMetrics).logRangingInitEvent(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager) .onRangingOpenFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mNativeUwbManager).deInitSession(eq(TEST_SESSION_ID), eq(TEST_CHIP_ID)); } @Test public void openRanging_wrongIdleState() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); // stub for openRanging conditions when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_ERROR).when(uwbSession).getSessionState(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(mUwbMetrics).logRangingInitEvent(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager) .onRangingOpenFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mNativeUwbManager).deInitSession(eq(TEST_SESSION_ID), eq(TEST_CHIP_ID)); } @Test public void testInitSessionWithNonSystemAppInFg() throws Exception { when(mUwbInjector.isSystemApp(UID, PACKAGE_NAME)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID, PACKAGE_NAME)).thenReturn(true); UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); // OPEN_RANGING message scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); assertThat(mTestLooper.isIdle()).isFalse(); } @Test public void testInitSessionWithNonSystemAppNotInFg() throws Exception { when(mUwbInjector.isSystemApp(UID, PACKAGE_NAME)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID, PACKAGE_NAME)).thenReturn(false); UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); verify(uwbSession.getIUwbRangingCallbacks()).onRangingOpenFailed( eq(uwbSession.getSessionHandle()), eq(StateChangeReason.SYSTEM_POLICY), any()); // No OPEN_RANGING message scheduled. assertThat(mTestLooper.isIdle()).isFalse(); } @Test public void testInitSessionWithNonSystemAppNotInFg_WhenBgRangingEnabled() throws Exception { when(mDeviceConfigFacade.isBackgroundRangingEnabled()).thenReturn(true); when(mUwbInjector.isSystemApp(UID, PACKAGE_NAME)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID, PACKAGE_NAME)).thenReturn(false); UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); // OPEN_RANGING message scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); assertThat(mTestLooper.isIdle()).isFalse(); } private AttributionSource.Builder setNextAttributionSource( @NonNull AttributionSource.Builder builder, @Nullable AttributionSource nextAttributionSource) { if (isAtLeastV() && Flags.setNextAttributionSource()) { return builder.setNextAttributionSource(nextAttributionSource); } else { return builder.setNext(nextAttributionSource); } } private UwbSession initUwbSessionForNonSystemAppInFgInChain() throws Exception { when(mUwbInjector.isSystemApp(UID_2, PACKAGE_NAME_2)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID_2, PACKAGE_NAME_2)) .thenReturn(true); // simulate system app triggered the request on behalf of a fg app in fg. AttributionSource.Builder builder = new AttributionSource.Builder(UID) .setPackageName(PACKAGE_NAME); builder = setNextAttributionSource(builder, new AttributionSource.Builder(UID_2) .setPackageName(PACKAGE_NAME_2) .build()); AttributionSource attributionSource = builder.build(); UwbSession uwbSession = setUpUwbSessionForExecution(attributionSource); mUwbSessionManager.initSession(attributionSource, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); return uwbSession; } private UwbSession initUwbSessionForNonSystemAppNotInFgInChain() throws Exception { when(mUwbInjector.isSystemApp(UID_2, PACKAGE_NAME_2)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID_2, PACKAGE_NAME_2)) .thenReturn(false); // simulate system app triggered the request on behalf of a fg app in fg. AttributionSource attributionSource = new AttributionSource.Builder(UID) .setPackageName(PACKAGE_NAME) .setNext(new AttributionSource.Builder(UID_2) .setPackageName(PACKAGE_NAME_2) .build()) .build(); UwbSession uwbSession = setUpUwbSessionForExecution(attributionSource); mUwbSessionManager.initSession(attributionSource, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); return uwbSession; } @Test public void testOpenRangingWithNonSystemAppInFgInChain() throws Exception { initUwbSessionForNonSystemAppInFgInChain(); // OPEN_RANGING message scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); assertThat(mTestLooper.isIdle()).isFalse(); } @Test public void testOpenRangingWithNonSystemAppInFgInChain_MoveToBgAndStayThere() throws Exception { UwbSession uwbSession = initUwbSessionForNonSystemAppInFgInChain(); // Verify that an OPEN_RANGING message was scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); // Start Ranging when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Move the non-privileged app to background, this should result in the session getting // reconfigured (to disable the ranging data notifications). mOnUidImportanceListenerArgumentCaptor.getValue().onUidImportance( UID_2, IMPORTANCE_BACKGROUND); mTestLooper.dispatchAll(); ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_1_1)); FiraRangingReconfigureParams firaParams = (FiraRangingReconfigureParams) paramsArgumentCaptor.getValue(); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo( FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE); verify(mUwbSessionNotificationManager, never()).onRangingReconfigured(eq(uwbSession)); // Verify the appropriate timer is setup. ArgumentCaptor alarmListenerCaptor = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); verify(mAlarmManager).setExact( anyInt(), anyLong(), eq(UwbSession.NON_PRIVILEGED_BG_APP_TIMER_TAG), alarmListenerCaptor.capture(), any()); assertThat(alarmListenerCaptor.getValue()).isNotNull(); // Now fire the timer callback. doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); alarmListenerCaptor.getValue().onAlarm(); // Expect session stop. mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStoppedWithApiReasonCode( eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY), any()); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void testOpenRangingWithNonSystemAppInFgInChain_MoveToBgAndStayThere_WhenBgRangingEnabled() throws Exception { when(mDeviceConfigFacade.isBackgroundRangingEnabled()).thenReturn(true); UwbSession uwbSession = initUwbSessionForNonSystemAppInFgInChain(); // Verify that an OPEN_RANGING message was scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); // Start Ranging when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Move the non-privileged app to background, this should result in the session getting // reconfigured (to disable the ranging data notifications). mOnUidImportanceListenerArgumentCaptor.getValue().onUidImportance( UID_2, IMPORTANCE_BACKGROUND); mTestLooper.dispatchAll(); ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_1_1)); FiraRangingReconfigureParams firaParams = (FiraRangingReconfigureParams) paramsArgumentCaptor.getValue(); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo( FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE); verify(mUwbSessionNotificationManager, never()).onRangingReconfigured(eq(uwbSession)); // Verify the timer is not setup. verify(mAlarmManager, never()).setExact( anyInt(), anyLong(), eq(UwbSession.NON_PRIVILEGED_BG_APP_TIMER_TAG), any(), any()); } @Test public void testOpenRangingWithNonSystemAppInFgInChain_StartInBg_WhenBgRangingEnabled() throws Exception { when(mDeviceConfigFacade.isBackgroundRangingEnabled()).thenReturn(true); UwbSession uwbSession = initUwbSessionForNonSystemAppNotInFgInChain(); // Verify that an OPEN_RANGING message was scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); // Start Ranging when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Ensure that we reconfigure the session immediately to disable range data notifications. mTestLooper.dispatchAll(); ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_1_1)); FiraRangingReconfigureParams firaParams = (FiraRangingReconfigureParams) paramsArgumentCaptor.getValue(); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo( FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE); verify(mUwbSessionNotificationManager, never()).onRangingReconfigured(eq(uwbSession)); // Verify the timer is not setup. verify(mAlarmManager, never()).setExact( anyInt(), anyLong(), eq(UwbSession.NON_PRIVILEGED_BG_APP_TIMER_TAG), any(), any()); } @Test public void testOpenRangingWithNonSystemAppInFgInChain_MoveToBgAndFg() throws Exception { UwbSession uwbSession = initUwbSessionForNonSystemAppInFgInChain(); // OPEN_RANGING message scheduled. assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); mTestLooper.dispatchAll(); // Move to background. mOnUidImportanceListenerArgumentCaptor.getValue().onUidImportance( UID_2, IMPORTANCE_BACKGROUND); mTestLooper.dispatchAll(); ArgumentCaptor paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class); verify(mUwbConfigurationManager).setAppConfigurations( eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_1_1)); FiraRangingReconfigureParams firaParams = (FiraRangingReconfigureParams) paramsArgumentCaptor.getValue(); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo( FiraParams.RANGE_DATA_NTF_CONFIG_DISABLE); verify(mUwbSessionNotificationManager, never()).onRangingReconfigured(eq(uwbSession)); // Move to foreground. mOnUidImportanceListenerArgumentCaptor.getValue().onUidImportance( UID_2, IMPORTANCE_FOREGROUND); mTestLooper.dispatchAll(); paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class); verify(mUwbConfigurationManager, times(2)).setAppConfigurations( eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID), eq(FIRA_VERSION_1_1)); firaParams = (FiraRangingReconfigureParams) paramsArgumentCaptor.getValue(); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo( FiraParams.RANGE_DATA_NTF_CONFIG_ENABLE); verify(mUwbSessionNotificationManager, never()).onRangingReconfigured(eq(uwbSession)); } @Test public void testOpenRangingWithNonSystemAppInFgInChain_MoveToBgTriggersSessionPriorityChange() throws Exception { UwbSession uwbSession = initUwbSessionForNonSystemAppInFgInChain(); assertThat(uwbSession.getStackSessionPriority()).isEqualTo(UwbSession.FG_SESSION_PRIORITY); assertThat(mTestLooper.nextMessage().what).isEqualTo(SESSION_OPEN_RANGING); mTestLooper.dispatchAll(); // Move to background. when(mUwbInjector.isForegroundAppOrService(UID_2, PACKAGE_NAME_2)) .thenReturn(false); mOnUidImportanceListenerArgumentCaptor.getValue().onUidImportance( UID_2, ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED); mTestLooper.dispatchAll(); assertThat(uwbSession.getStackSessionPriority()).isEqualTo(UwbSession.BG_SESSION_PRIORITY); } @Test public void testOpenRangingWithNonSystemAppNotInFgInChain() throws Exception { when(mUwbInjector.isSystemApp(UID_2, PACKAGE_NAME_2)).thenReturn(false); when(mUwbInjector.isForegroundAppOrService(UID_2, PACKAGE_NAME_2)) .thenReturn(false); // simulate system app triggered the request on behalf of a fg app not in fg. AttributionSource.Builder builder = new AttributionSource.Builder(UID) .setPackageName(PACKAGE_NAME); builder = setNextAttributionSource(builder, new AttributionSource.Builder(UID_2) .setPackageName(PACKAGE_NAME_2) .build()); AttributionSource attributionSource = builder.build(); UwbSession uwbSession = setUpUwbSessionForExecution(attributionSource); mUwbSessionManager.initSession(attributionSource, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); verify(uwbSession.getIUwbRangingCallbacks()).onRangingOpenFailed( eq(uwbSession.getSessionHandle()), eq(StateChangeReason.SYSTEM_POLICY), any()); // No OPEN_RANGING message scheduled. assertThat(mTestLooper.isIdle()).isFalse(); } private UwbSession prepareExistingUwbSessionCommon(UwbSession uwbSession) throws Exception { mUwbSessionManager.initSession( ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), uwbSession.getSessionId(), uwbSession.getSessionType(), uwbSession.getProtocolName(), uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), uwbSession.getChipId()); mTestLooper.nextMessage(); // remove the OPEN_RANGING msg; assertThat(mTestLooper.isIdle()).isFalse(); return uwbSession; } private UwbSession prepareExistingUwbSession(Params params) throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE, params); return prepareExistingUwbSessionCommon(uwbSession); } private UwbSession prepareExistingUwbSession() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); return prepareExistingUwbSessionCommon(uwbSession); } private UwbSession prepareExistingUwbSessionActive(Params params) throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE, params); uwbSession = prepareExistingUwbSessionCommon(uwbSession); return prepareExistingUwbSessionActiveCommon(uwbSession); } private UwbSession prepareExistingUwbSessionActive() throws Exception { UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE); uwbSession = prepareExistingUwbSessionCommon(uwbSession); return prepareExistingUwbSessionActiveCommon(uwbSession); } private UwbSession prepareExistingUwbSessionActiveCommon(UwbSession uwbSession) throws Exception { // Setup the UwbSession to start ranging (and move it to active state). doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); return uwbSession; } private UwbSession prepareExistingCccUwbSession() throws Exception { UwbSession uwbSession = setUpCccUwbSessionForExecution(CCC_OPEN_RANGING_PARAMS_DEFAULT); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, CccParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.nextMessage(); // remove the OPEN_RANGING msg; assertThat(mTestLooper.isIdle()).isFalse(); return uwbSession; } private UwbSession prepareExistingAliroUwbSession() throws Exception { UwbSession uwbSession = setUpAliroUwbSessionForExecution(ALIRO_OPEN_RANGING_PARAMS_DEFAULT); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, AliroParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.nextMessage(); // remove the OPEN_RANGING msg; assertThat(mTestLooper.isIdle()).isFalse(); return uwbSession; } private UwbSession prepareExistingUwbSessionWithSessionType(byte sessionType, Params params) throws Exception { UwbSession uwbSession = setUpUwbSessionForExecutionWithSessionType(sessionType, params); return prepareExistingUwbSessionCommon(uwbSession); } @Test public void reconfigure_calledSuccess() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams params = new FiraRangingReconfigureParams.Builder() .setBlockStrideLength(10) .setRangeDataNtfConfig(1) .setRangeDataProximityFar(10) .setRangeDataProximityNear(2) .build(); int actualStatus = mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), params); assertThat(actualStatus).isEqualTo(0); assertThat(mTestLooper.nextMessage().what) .isEqualTo(UwbSessionManager.SESSION_RECONFIG_RANGING); // Verify the cache has been updated. FiraOpenSessionParams firaParams = (FiraOpenSessionParams) uwbSession.getParams(); assertThat(firaParams.getBlockStrideLength()).isEqualTo(10); assertThat(firaParams.getRangeDataNtfConfig()).isEqualTo(1); assertThat(firaParams.getRangeDataNtfProximityFar()).isEqualTo(10); assertThat(firaParams.getRangeDataNtfProximityNear()).isEqualTo(2); } @Test public void startRanging_sessionStateIdle() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); assertThat(mTestLooper.isIdle()).isTrue(); assertThat(mTestLooper.nextMessage().what).isEqualTo(2); // SESSION_START_RANGING } @Test public void startRanging_sessionStateActive() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); assertThat(mTestLooper.isIdle()).isFalse(); verify(mUwbSessionNotificationManager).onRangingStartFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_REJECTED)); } @Test public void startRanging_sessionStateError() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ERROR) .when(uwbSession).getSessionState(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); assertThat(mTestLooper.isIdle()).isFalse(); verify(mUwbSessionNotificationManager).onRangingStartFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execStartRanging_success_fira_1_x_relativeUwbInitiationTime() throws Exception { FiraProtocolVersion protocolVersion = new FiraProtocolVersion(1, 1); Params startRangingParams = setupFiraParams(protocolVersion); UwbSession uwbSession = prepareExistingUwbSession(); do_execStartRanging_success_uwbs_1_x_relativeUwbInitiationTime( uwbSession, startRangingParams, /* rangingStartedParams = */ null, protocolVersion); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Verify that setAppConfigurations() is not called for a Fira ranging session, as the // "params.mInitiationTime" field is not set, and so no re-configuration is needed // before the UWB ranging is started. verify(mUwbConfigurationManager, never()).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_1_1)); } @Test public void execStartRanging_success_ccc_1_x_relativeUwbInitiationTime() throws Exception { UwbSession uwbSession = prepareExistingCccUwbSession(); CccStartRangingParams cccStartRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .build(); CccRangingStartedParams cccRangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_1_x_relativeUwbInitiationTime( uwbSession, cccStartRangingParams, cccRangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); // Verify the absolute UWB initiation time is not set in the CccOpenRangingParams. CccOpenRangingParams cccOpenRangingParams = (CccOpenRangingParams) uwbSession.getParams(); assertThat(cccOpenRangingParams.getAbsoluteInitiationTimeUs()).isEqualTo(0); } @Test public void execStartRanging_success_aliro_1_x_relativeUwbInitiationTime() throws Exception { UwbSession uwbSession = prepareExistingAliroUwbSession(); AliroStartRangingParams aliroStartRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .build(); AliroRangingStartedParams aliroRangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_1_x_relativeUwbInitiationTime( uwbSession, aliroStartRangingParams, aliroRangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); // Verify the absolute UWB initiation time is not set in the AliroOpenRangingParams. AliroOpenRangingParams aliroOpenRangingParams = (AliroOpenRangingParams) uwbSession.getParams(); assertThat(aliroOpenRangingParams.getAbsoluteInitiationTimeUs()).isEqualTo(0); } private void do_execStartRanging_success_uwbs_1_x_relativeUwbInitiationTime( UwbSession uwbSession, Params startRangingParams, Params rangingStartedParams, ProtocolVersion protocolVersion) throws Exception { // Setup the UWBS to return Fira version as 1.1. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( UWB_DEVICE_INFO_RESPONSE_1_1); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mUwbConfigurationManager.getAppConfigurations( eq(TEST_SESSION_ID), anyString(), any(), any(), eq(TEST_CHIP_ID), eq(protocolVersion))) .thenReturn(new Pair<>(UwbUciConstants.STATUS_CODE_OK, rangingStartedParams)); // Start ranging on the UWB session mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), startRangingParams); mTestLooper.dispatchAll(); // Verify that the ranging started successfully. verify(mNativeUwbManager).startRanging(eq(TEST_SESSION_ID), anyString()); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Verify that queryUwbsTimestampMicros() is not called for FiRa 1.x. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); } @Test public void execStartRanging_success_fira_2_0_noUwbInitiationTimeConfigured() throws Exception { Params firaParams = setupFiraParams(FIRA_VERSION_2_0); UwbSession uwbSession = prepareExistingUwbSession(firaParams); do_execStartRanging_success_uwbs_2_0_noUwbInitiationTimeConfigured( uwbSession, /* startRangingParams = */ firaParams, /* rangingStartedParams = */ firaParams, FIRA_VERSION_2_0); // Verify that setAppConfigurations() is not called, as the "params.mInitiationTime" field // is not set, and so no re-configuration is needed for a Fira session, before the // UWB ranging is started. verify(mUwbConfigurationManager, never()).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } @Test public void execStartRanging_success_ccc_2_0_noUwbInitiationTimeConfigured() throws Exception { UwbSession uwbSession = prepareExistingCccUwbSession(); Params startRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .build(); CccRangingStartedParams rangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0_noUwbInitiationTimeConfigured( uwbSession, startRangingParams, rangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); } @Test public void execStartRanging_success_aliro_2_0_noUwbInitiationTimeConfigured() throws Exception { UwbSession uwbSession = prepareExistingAliroUwbSession(); Params startRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .build(); AliroRangingStartedParams rangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0_noUwbInitiationTimeConfigured( uwbSession, startRangingParams, rangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); } // Test UWB StartRanging on a Fira UCI version 2.0+ device, when the App doesn't configure // any UWB initiation time (relative or absolute). In this case, the UwbSessionManager is not // expected to query the UWBS timestamp. private void do_execStartRanging_success_uwbs_2_0_noUwbInitiationTimeConfigured( UwbSession uwbSession, Params startRangingParams, Params rangingStartedParams, ProtocolVersion protocolVersion) throws Exception { // Setup the UWBS to return Fira UCI version as 2.0. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( UWB_DEVICE_INFO_RESPONSE_2_0); // Setup for start ranging. doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); when(mUwbConfigurationManager.getAppConfigurations( eq(TEST_SESSION_ID), anyString(), any(), any(), eq(TEST_CHIP_ID), eq(protocolVersion))) .thenReturn(new Pair<>(UwbUciConstants.STATUS_CODE_OK, rangingStartedParams)); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), startRangingParams); mTestLooper.dispatchAll(); // Verify that the UWB ranging successfully started. verify(mNativeUwbManager).startRanging(eq(TEST_SESSION_ID), anyString()); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Verify that queryUwbsTimestampMicros() is not called. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); } @Test public void execStartRanging_success_fira_2_0_absoluteUwbInitiationTimeIsComputed() throws Exception { // Setup the UWBS to return Fira UCI version as 2.0. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( UWB_DEVICE_INFO_RESPONSE_2_0); // Setup the AbsoluteInitationTime in the FiraOpenSessionParams. Params params = setupFiraParams(FIRA_VERSION_2_0); FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder((FiraOpenSessionParams) params) .setInitiationTime(100L) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); // Setup for start ranging. doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mUwbServiceCore.queryUwbsTimestampMicros()).thenReturn(UWBS_TIMESTAMP); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), params); mTestLooper.dispatchAll(); // Verify that queryUwbsTimestampMicros() is called. Currently unable to verify that the // FiraOpenSessionParams is changed and the absoluteInitiationTime field set in it, as // equals() is not implemented. verify(mUwbServiceCore).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } // Test CCC StartRanging on a Fira UCI version 2.0+ device, when the App configures a relative // UWB initiation time, and the computation of an absolute UWB initiation time is enabled on // the device. In this case, the UwbSessionManager is expected to query the UWBS timestamp. @Test public void execStartRanging_success_ccc_2_0_absoluteInitiationTimeComputationIsComputed() throws Exception { // Setup the flag to be "true", so that absolute UWB initiation time computation is // enabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = prepareExistingCccUwbSession(); Params cccStartRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setInitiationTimeMs(100) .build(); CccRangingStartedParams cccRangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, cccStartRangingParams, cccRangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is called. Currently unable to verify that the // CccOpenRangingParams is changed and the absoluteInitiationTime field set in it, as // equals() is not implemented. verify(mUwbServiceCore).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } // Test ALIRO StartRanging on a Fira UCI version 2.0+ device, when the App configures a relative // UWB initiation time, and the computation of an absolute UWB initiation time is enabled on // the device. In this case, the UwbSessionManager is expected to query the UWBS timestamp. @Test public void execStartRanging_success_aliro_2_0_absoluteInitiationTimeComputationIsComputed() throws Exception { // Setup the flag to be "true", so that absolute UWB initiation time computation is // enabled for a CCC ranging session. // // We currently re-use the CCC flag for ALIRO. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = prepareExistingAliroUwbSession(); Params aliroStartRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setInitiationTimeMs(100) .build(); AliroRangingStartedParams aliroRangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, aliroStartRangingParams, aliroRangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is called. Currently unable to verify that the // AliroOpenRangingParams is changed and the absoluteInitiationTime field set in it, as // equals() is not implemented. verify(mUwbServiceCore).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } // Test CCC StartRanging on a Fira UCI version 2.0+ device, when the App configures a relative // UWB initiation time, and the computation of an absolute UWB initiation time is disabled on // the device. In this case, the UwbSessionManager is not expected to query the UWBS timestamp. @Test public void execStartRanging_success_ccc_2_0_absoluteInitiationTimeComputationIsDisabled() throws Exception { // Setup the flag to "false" (which is also the default value), so that absolute // UWB initiation time computation is disabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(false); UwbSession uwbSession = prepareExistingCccUwbSession(); Params cccStartRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setInitiationTimeMs(100) .build(); CccRangingStartedParams cccRangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, cccStartRangingParams, cccRangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is not called. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } // Test ALIRO StartRanging on a Fira UCI version 2.0+ device, when the App configures a relative // UWB initiation time, and the computation of an absolute UWB initiation time is disabled on // the device. In this case, the UwbSessionManager is not expected to query the UWBS timestamp. @Test public void execStartRanging_success_aliro_2_0_absoluteInitiationTimeComputationIsDisabled() throws Exception { // Setup the flag to "false" (which is also the default value), so that absolute // UWB initiation time computation is disabled for a CCC ranging session. // // We currently re-use the CCC flag for ALIRO. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(false); UwbSession uwbSession = prepareExistingAliroUwbSession(); Params aliroStartRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setInitiationTimeMs(100) .build(); AliroRangingStartedParams aliroRangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, aliroStartRangingParams, aliroRangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is not called. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } // Test FiRa StartRanging on a Fira UCI version 2.0+ device, when the App configures an absolute // UWB initiation time. In this case, the UwbSessionManager is not expected to query the UWBS // timestamp. @Test public void execStartRanging_success_fira_2_0_absoluteUwbInitiationTimeUserConfigured() throws Exception { Params params = setupFiraParams(FIRA_VERSION_2_0); // Setup the AbsoluteInitationTime in the FiraOpenSessionParams. FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder((FiraOpenSessionParams) params) .setAbsoluteInitiationTime(1000000L) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); do_execStartRanging_success_uwbs_2_0(uwbSession, params, null, FIRA_VERSION_2_0); // Verify that queryUwbsTimestampMicros() isn't called (which is the expected behavior as // the firaParams has the absolute_initiation_time field set). verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); } // Test CCC StartRanging on a Fira UCI version 2.0+ device, when the App configures an absolute // UWB initiation time. In this case, the UwbSessionManager is not expected to query the UWBS // timestamp. @Test public void execStartRanging_success_ccc_2_0_absoluteInitiationTimeUserConfigured() throws Exception { // Setup the flag to be "true", so that absolute UWB initiation time computation is // enabled for a CCC ranging session. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = prepareExistingCccUwbSession(); CccStartRangingParams cccStartRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setAbsoluteInitiationTimeUs(8000) .build(); CccRangingStartedParams cccRangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, cccStartRangingParams, cccRangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is not called when it is configured with // CccStartRangingParams verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } // Test ALIRO StartRanging on a Fira UCI version 2.0+ device, when the App configures an // absolute UWB initiation time. In this case, the UwbSessionManager is not expected to query // the UWBS timestamp. @Test public void execStartRanging_success_aliro_2_0_absoluteInitiationTimeUserConfigured() throws Exception { // Setup the flag to be "true", so that absolute UWB initiation time computation is // enabled for a ALIRO ranging session. // // We currently use the CCC flag for ALIRO sessions also. when(mDeviceConfigFacade.isCccAbsoluteUwbInitiationTimeEnabled()).thenReturn(true); UwbSession uwbSession = prepareExistingAliroUwbSession(); AliroStartRangingParams aliroStartRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(4) .setAbsoluteInitiationTimeUs(8000) .build(); AliroRangingStartedParams aliroRangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_execStartRanging_success_uwbs_2_0(uwbSession, aliroStartRangingParams, aliroRangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); // Verify that queryUwbsTimestampMicros() is not called when it is configured with // AliroStartRangingParams. verify(mUwbServiceCore, never()).queryUwbsTimestampMicros(); verify(mUwbConfigurationManager).setAppConfigurations( anyInt(), any(), any(), eq(FIRA_VERSION_2_0)); } private void do_execStartRanging_success_uwbs_2_0(UwbSession uwbSession, Params cccStartRangingParams, Params rangingStartedParams, ProtocolVersion protocolVersion) throws Exception { // Setup the UWBS to return Fira UCI version as 2.0. when(mUwbServiceCore.getCachedDeviceInfoResponse(TEST_CHIP_ID)).thenReturn( UWB_DEVICE_INFO_RESPONSE_2_0); // Setup for start ranging. doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mUwbServiceCore.queryUwbsTimestampMicros()).thenReturn(UWBS_TIMESTAMP); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); when(mUwbConfigurationManager.getAppConfigurations( eq(TEST_SESSION_ID), anyString(), any(), any(), eq(TEST_CHIP_ID), eq(protocolVersion))) .thenReturn(new Pair<>(UwbUciConstants.STATUS_CODE_OK, rangingStartedParams)); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), cccStartRangingParams); mTestLooper.dispatchAll(); // Verify that the UWB ranging session was successfully started. verify(mNativeUwbManager).startRanging(eq(TEST_SESSION_ID), anyString()); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } @Test public void execStartRanging_onRangeDataNotification() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Now send a range data notification. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); } @Test public void execStartRanging_twoWay_onRangeDataNotificationContinuousErrors() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); UwbAddress controleeAddr = setUpControlee(uwbSession, MAC_ADDRESSING_MODE_SHORT); startRanging(uwbSession); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Now send a range data notification with an error. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); // Verify that an alarm is started for the controlee ArgumentCaptor addressCaptor = ArgumentCaptor.forClass(UwbAddress.class); ArgumentCaptor alarmListenerCaptor = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); verify(uwbSession.mMulticastRangingErrorStreakTimerListeners).put( addressCaptor.capture(), alarmListenerCaptor.capture() ); verify(mAlarmManager).setExact( anyInt(), anyLong(), anyString(), eq(alarmListenerCaptor.getValue()), any()); assertThat(addressCaptor.getValue()).isEqualTo(controleeAddr); assertThat(alarmListenerCaptor.getValue()).isNotNull(); // Send one more error uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); // Verify that the alarm is not cancelled verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class)); // set up for stop ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Now fire the timer callback. alarmListenerCaptor.getValue().onAlarm(); // Expect session stop. mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY), any()); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void execStartRanging_owrAoa_onRangeDataNotificationContinuousErrors() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); startRanging(uwbSession); // Now send a range data notification with an error. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); ArgumentCaptor alarmListenerCaptor = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); verify(mAlarmManager).setExact( anyInt(), anyLong(), anyString(), alarmListenerCaptor.capture(), any()); assertThat(alarmListenerCaptor.getValue()).isNotNull(); // Send one more error and ensure that the timer is not cancelled. uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class)); // set up for stop ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Now fire the timer callback. alarmListenerCaptor.getValue().onAlarm(); // Expect session stop. mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY), any()); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void execStartRanging_onRangeDataNotificationContinuousErrors_WhenErrorStreakTimerDisabled() throws Exception { when(mDeviceConfigFacade.isRangingErrorStreakTimerEnabled()).thenReturn(false); UwbSession uwbSession = prepareExistingUwbSession(); startRanging(uwbSession); // Now send a range data notification with an error. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); // Ensure error streak timer is not started. verify(mAlarmManager, never()).setExact( anyInt(), anyLong(), anyString(), any(), any()); } @Test public void execStartRanging_onRangeDataNotificationErrorFollowedBySuccess() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); UwbAddress controleeAddr = setUpControlee(uwbSession, MAC_ADDRESSING_MODE_SHORT); startRanging(uwbSession); // Now send a range data notification with an error. UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData); // Verify that an alarm is started for the controlee. ArgumentCaptor addressCaptor = ArgumentCaptor.forClass(UwbAddress.class); ArgumentCaptor alarmListenerCaptor = ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); verify(uwbSession.mMulticastRangingErrorStreakTimerListeners).put( addressCaptor.capture(), alarmListenerCaptor.capture() ); verify(mAlarmManager).setExact( anyInt(), anyLong(), anyString(), eq(alarmListenerCaptor.getValue()), any()); assertThat(addressCaptor.getValue()).isEqualTo(controleeAddr); assertThat(alarmListenerCaptor.getValue()).isNotNull(); // Actually do the putting so that we can check for removal later. uwbSession.mMulticastRangingErrorStreakTimerListeners.put(addressCaptor.getValue(), alarmListenerCaptor.getValue()); // Send successful data and ensure that the controlee's timer is cancelled. uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_SHORT, UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbSessionNotificationManager).onRangingResult(eq(uwbSession), eq(uwbRangingData)); verify(mAlarmManager).cancel(eq(alarmListenerCaptor.getValue())); verify(uwbSession.mMulticastRangingErrorStreakTimerListeners) .remove(eq(addressCaptor.getValue())); } @Test public void session_receivedDataInfo() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // Setup the UwbSession to have multiple data packets (being received) for multiple remote // devices. This includes some duplicate packets (same sequence number from same remote // device), which should be ignored. UwbSessionManager.ReceivedDataInfo deviceOnePacketOne = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM); UwbSessionManager.ReceivedDataInfo deviceOnePacketTwo = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM_1); UwbSessionManager.ReceivedDataInfo deviceTwoPacketOne = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_2_LONG, DATA_SEQUENCE_NUM); UwbSessionManager.ReceivedDataInfo deviceTwoPacketTwo = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_2_LONG, DATA_SEQUENCE_NUM_1); when(mDeviceConfigFacade.getRxDataMaxPacketsToStore()) .thenReturn(MAX_RX_DATA_PACKETS_TO_STORE); uwbSession.addReceivedDataInfo(deviceOnePacketOne); uwbSession.addReceivedDataInfo(deviceOnePacketTwo); uwbSession.addReceivedDataInfo(deviceOnePacketOne); uwbSession.addReceivedDataInfo(deviceTwoPacketOne); uwbSession.addReceivedDataInfo(deviceTwoPacketTwo); uwbSession.addReceivedDataInfo(deviceTwoPacketOne); // Verify that the first call to getAllReceivedDataInfo() for a device returns all it's // received packets, and the second call receives an empty list. assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of(deviceOnePacketOne, deviceOnePacketTwo)); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of()); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_2_LONG)).isEqualTo( List.of(deviceTwoPacketOne, deviceTwoPacketTwo)); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_2_LONG)).isEqualTo( List.of()); } @Test public void session_receivedDataInfo_maxCapacity() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); UwbSessionManager.ReceivedDataInfo rxPacketOne = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM + 1); UwbSessionManager.ReceivedDataInfo rxPacketTwo = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM + 2); UwbSessionManager.ReceivedDataInfo rxPacketThree = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM + 3); UwbSessionManager.ReceivedDataInfo rxPacketFour = buildReceivedDataInfo( PEER_EXTENDED_MAC_ADDRESS_LONG, DATA_SEQUENCE_NUM + 4); // Setup the UwbSession to have multiple data packets (being received) from one remote // device, such that it's at the capacity. We send the packets out-of-order, but do want // to extract them in order. when(mDeviceConfigFacade.getRxDataMaxPacketsToStore()).thenReturn(3); // Case 1 - Setup the UwbSession to have multiple Rx data packets (beyond capacity), such // that the last packet is the smallest one and should be dropped. uwbSession.addReceivedDataInfo(rxPacketTwo); uwbSession.addReceivedDataInfo(rxPacketFour); uwbSession.addReceivedDataInfo(rxPacketThree); uwbSession.addReceivedDataInfo(rxPacketOne); // Verify that the first call to getAllReceivedDataInfo() returns the max capacity number of // packets (in-order), and the second call receives an empty list. assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of(rxPacketTwo, rxPacketThree, rxPacketFour)); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of()); // Case 2 - Setup the UwbSession to have multiple Rx data packets (beyond capacity), such // that one of the stored packets is the smallest one and should be dropped. uwbSession.addReceivedDataInfo(rxPacketOne); uwbSession.addReceivedDataInfo(rxPacketTwo); uwbSession.addReceivedDataInfo(rxPacketFour); uwbSession.addReceivedDataInfo(rxPacketThree); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of(rxPacketTwo, rxPacketThree, rxPacketFour)); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of()); // Case 3 - Setup the UwbSession to have multiple Rx data packets (beyond capacity), such // that one of the stored packets is repeated. The repeated packet should be ignored. uwbSession.addReceivedDataInfo(rxPacketTwo); uwbSession.addReceivedDataInfo(rxPacketFour); uwbSession.addReceivedDataInfo(rxPacketThree); uwbSession.addReceivedDataInfo(rxPacketFour); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of(rxPacketTwo, rxPacketThree, rxPacketFour)); assertThat(uwbSession.getAllReceivedDataInfo(PEER_EXTENDED_MAC_ADDRESS_LONG)).isEqualTo( List.of()); } @Test public void execStartCccRanging_success() throws Exception { UwbSession uwbSession = prepareExistingCccUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); CccStartRangingParams cccStartRangingParams = new CccStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(8) .build(); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), cccStartRangingParams); mTestLooper.dispatchAll(); // Verify the update logic. CccOpenRangingParams cccOpenRangingParams = (CccOpenRangingParams) uwbSession.getParams(); assertThat(cccOpenRangingParams.getRanMultiplier()).isEqualTo(8); } @Test public void execStartAliroRanging_success() throws Exception { UwbSession uwbSession = prepareExistingAliroUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); AliroStartRangingParams aliroStartRangingParams = new AliroStartRangingParams.Builder() .setSessionId(TEST_SESSION_ID) .setRanMultiplier(8) .build(); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), aliroStartRangingParams); mTestLooper.dispatchAll(); // Verify the update logic. AliroOpenRangingParams aliroOpenRangingParams = (AliroOpenRangingParams) uwbSession.getParams(); assertThat(aliroOpenRangingParams.getRanMultiplier()).isEqualTo(8); } @Test public void execStartCccRangingWithNoStartParams_success() throws Exception { UwbSession uwbSession = prepareExistingCccUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), null /* params */); mTestLooper.dispatchAll(); // Verify that RAN multiplier from open is used. CccOpenRangingParams cccOpenRangingParams = (CccOpenRangingParams) uwbSession.getParams(); assertThat(cccOpenRangingParams.getRanMultiplier()).isEqualTo(4); } @Test public void execStartAliroRangingWithNoStartParams_success() throws Exception { UwbSession uwbSession = prepareExistingAliroUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), null /* params */); mTestLooper.dispatchAll(); // Verify that RAN multiplier from open is used. AliroOpenRangingParams aliroOpenRangingParams = (AliroOpenRangingParams) uwbSession.getParams(); assertThat(aliroOpenRangingParams.getRanMultiplier()).isEqualTo(4); } @Test public void execStartRanging_executionException() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenThrow(new IllegalStateException()); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execStartRanging_nativeStartRangingFailed() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStartFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execStartRanging_wrongSessionState() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ERROR) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); // In this scenario, there is no SESSION_STATUS_NTF received, so send an undefined // reasonCode (-1). verify(mUwbSessionNotificationManager).onRangingStartFailedWithUciReasonCode( eq(uwbSession), eq(-1)); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execStartRanging_sessionStateIdle_reasonSessionKeyNotFound() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for start ranging - it fails and session_state stays at IDLE. doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // UWBS sends the SESSION_STATS_NTF with ReasonCode as REASON_ERROR_SESSION_KEY_NOT_FOUND. mUwbSessionManager.onSessionStatusNotificationReceived( TEST_SESSION_ID, SESSION_TOKEN, UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.REASON_ERROR_SESSION_KEY_NOT_FOUND); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStartFailedWithUciReasonCode( eq(uwbSession), eq(UwbUciConstants.REASON_ERROR_SESSION_KEY_NOT_FOUND)); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST)); } private void doTest_sendData_success_validUwbSession(byte[] macAddress, int dataTransferStatus) throws Exception { UwbAddress uwbAddress = UwbAddress.fromBytes(macAddress); UwbSession uwbSession = prepareExistingUwbSession(); // Setup the UwbSession to start ranging (and move it to active state). doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging(uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); // Send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(macAddress), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.sendData( uwbSession.getSessionHandle(), uwbAddress, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(macAddress), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); // A DataTransferStatusNtf is received indicating success. mUwbSessionManager.onDataSendStatus( uwbSession.getSessionId(), dataTransferStatus, DATA_SEQUENCE_NUM, DATA_TRANSMISSION_COUNT); verify(mUwbSessionNotificationManager).onDataSent( eq(uwbSession), eq(uwbAddress), eq(PERSISTABLE_BUNDLE)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // extended MacAddress format). The DataTransferStatus notification returns a success status // code (STATUS_CODE_DATA_TRANSFER_REPETITION_OK). @Test public void sendData_success_validUwbSession_extendedMacAddress_statusRepetitionOk() throws Exception { doTest_sendData_success_validUwbSession( PEER_EXTENDED_MAC_ADDRESS, STATUS_CODE_DATA_TRANSFER_REPETITION_OK); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // extended MacAddress format). The DataTransferStatus notification returns a success status // code (STATUS_CODE_OK). @Test public void sendData_success_validUwbSession_extendedMacAddress_statusOk() throws Exception { doTest_sendData_success_validUwbSession(PEER_EXTENDED_MAC_ADDRESS, STATUS_CODE_OK); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // short MacAddress format). The DataTransferStatus notification returns a success status // code (STATUS_CODE_DATA_TRANSFER_REPETITION_OK). @Test public void sendData_success_validUwbSession_shortMacAddress_statusRepetitionOk() throws Exception { doTest_sendData_success_validUwbSession( PEER_EXTENDED_SHORT_MAC_ADDRESS, STATUS_CODE_DATA_TRANSFER_REPETITION_OK); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // short MacAddress format). The DataTransferStatus notification returns a success status // code (STATUS_CODE_OK). @Test public void sendData_success_validUwbSession_shortMacAddress_statusOk() throws Exception { doTest_sendData_success_validUwbSession(PEER_EXTENDED_SHORT_MAC_ADDRESS, STATUS_CODE_OK); } @Test public void sendData_missingSessionHandle() throws Exception { // Setup a UwbSession to start ranging (and move it to active state). prepareExistingUwbSessionActive(); // Send a Data packet with null SessionHandle, it should result in an error. mUwbSessionManager.sendData( null /* sessionHandle */, PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager, never()).sendData( eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(null), eq(PEER_EXTENDED_UWB_ADDRESS), eq(UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST), eq(PERSISTABLE_BUNDLE)); } @Test public void sendData_invalidUwbSessionHandle() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state), and a // different sessionHandle that doesn't map to the uwbSession. prepareExistingUwbSessionActive(); SessionHandle sessionHandle = new SessionHandle(HANDLE_ID, ATTRIBUTION_SOURCE, PID); // Send a Data packet on the non-active UWB Session. mUwbSessionManager.sendData( sessionHandle, PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager, never()).sendData( eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(null), eq(PEER_EXTENDED_UWB_ADDRESS), eq(UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST), eq(PERSISTABLE_BUNDLE)); } @Test public void sendData_invalidUwbSessionState() throws Exception { // Setup a uwbSession and don't start ranging, so it remains in IDLE state. UwbSession uwbSession = prepareExistingUwbSession(); doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); // Attempt to send data on the UWB session. mUwbSessionManager.sendData( uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, null); mTestLooper.dispatchNext(); verify(mNativeUwbManager, never()).sendData( eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(uwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), eq(UwbUciConstants.STATUS_CODE_FAILED), eq(PERSISTABLE_BUNDLE)); } @Test public void sendData_missingDataPayload() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); // Attempt to send data on the UWB session. mUwbSessionManager.sendData( uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, null); mTestLooper.dispatchNext(); verify(mNativeUwbManager, never()).sendData( eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(uwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), eq(UwbUciConstants.STATUS_CODE_INVALID_PARAM), eq(PERSISTABLE_BUNDLE)); } @Test public void sendData_missingRemoteDevice() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); // Attempt to send data on the UWB session. mUwbSessionManager.sendData( uwbSession.getSessionHandle(), null, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager, never()).sendData( eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(uwbSession), eq(null), eq(UwbUciConstants.STATUS_CODE_INVALID_PARAM), eq(PERSISTABLE_BUNDLE)); } @Test public void sendData_dataSendFailure() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); // Attempt to send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(uwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), eq(UwbUciConstants.STATUS_CODE_FAILED), eq(PERSISTABLE_BUNDLE)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void onDataSendStatus_sessionNotFound() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); clearInvocations(mUwbSessionNotificationManager); // Send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // We receive a DataTransferStatusNtf with a sessionId for a different UwbSession, so it // should be dropped (no onDataSend()/onDataSendFailure() notifications sent). mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID_2, STATUS_CODE_OK, DATA_SEQUENCE_NUM, DATA_TRANSMISSION_COUNT); verifyNoMoreInteractions(mUwbSessionNotificationManager); } @Test public void onDataSendStatus_dataSndPacketNotFound() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); clearInvocations(mUwbSessionNotificationManager); // Send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // We receive a DataTransferStatusNtf with an incorrect UCI sequence number (for which a // packet was never sent), so it should be dropped (no onDataSend()/onDataSendFailure() // notifications sent). mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_OK, DATA_SEQUENCE_NUM_1, DATA_TRANSMISSION_COUNT); verifyNoMoreInteractions(mUwbSessionNotificationManager); } @Test public void onDataSendStatus_errorStatus() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); clearInvocations(mUwbSessionNotificationManager); // Send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // We receive a DataTransferStatusNtf with an error status code. mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_DATA_TRANSFER_ERROR_DATA_TRANSFER, DATA_SEQUENCE_NUM, DATA_TRANSMISSION_COUNT); verify(mUwbSessionNotificationManager).onDataSendFailed( eq(uwbSession), eq(PEER_EXTENDED_UWB_ADDRESS), eq(STATUS_CODE_DATA_TRANSFER_ERROR_DATA_TRANSFER), eq(PERSISTABLE_BUNDLE)); } @Test public void onDataSendStatus_neverReceived() throws Exception { // Setup a uwbSession UwbSession to start ranging (and move it to active state). UwbSession uwbSession = prepareExistingUwbSessionActive(); clearInvocations(mUwbSessionNotificationManager); // Send data on the UWB session. when(mNativeUwbManager.sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); verify(mNativeUwbManager).sendData(eq(TEST_SESSION_ID), eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()), eq(DATA_SEQUENCE_NUM), eq(DATA_PAYLOAD), eq(TEST_CHIP_ID)); verify(mUwbMetrics).logDataTx(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // We never receive a DataTransferStatusNtf, so no onDataSend()/onDataSendFailure() // notifications are sent. verifyNoMoreInteractions(mUwbSessionNotificationManager); assertNotNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); // Eventually Session DeInit is called, and the stored SendDataInfo(s) should be deleted. mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); assertNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // short MacAddress format). Verifies the deletion of stored data depending upon the status // code (STATUS_CODE_DATA_TRANSFER_REPETITION_OK) when data repetition count = 0. @Test public void sendData_withZeroDataRepetitionCount() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_AND_IN_BAND_DATA) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionActive(params); assertThat(uwbSession.getDataRepetitionCount()).isEqualTo(0); // Send the Data packet and simulate the onDataSendStatus() callback being received. mUwbSessionManager.sendData( uwbSession.getSessionHandle(), PEER_EXTENDED_SHORT_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); // Since txCount is 0, stored data should not be deleted mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_DATA_TRANSFER_REPETITION_OK, DATA_SEQUENCE_NUM, 0); assertNotNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); // Since txCount = DataRepetitionCount, stored data should removed mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_DATA_TRANSFER_OK, DATA_SEQUENCE_NUM, 1); assertNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); } // Test case for scenario when a Data packet is successfully sent to a remote device (in // short MacAddress format). Verifies the deletion of stored data depending upon the status // code (STATUS_CODE_DATA_TRANSFER_REPETITION_OK) and data repetition count of the // DataTransferStatus notification. @Test public void sendData_withNonZeroDataRepetitionCount() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_AND_IN_BAND_DATA) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setDataRepetitionCount(DATA_TRANSMISSION_COUNT_3) .build(); UwbSession uwbSession = prepareExistingUwbSessionActive(params); assertThat(uwbSession.getDataRepetitionCount()).isEqualTo(DATA_TRANSMISSION_COUNT_3); // Send the Data packet and simulate the onDataSendStatus() callback being received. mUwbSessionManager.sendData( uwbSession.getSessionHandle(), PEER_EXTENDED_SHORT_UWB_ADDRESS, PERSISTABLE_BUNDLE, DATA_PAYLOAD); mTestLooper.dispatchNext(); mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_DATA_TRANSFER_REPETITION_OK, DATA_SEQUENCE_NUM, DATA_TRANSMISSION_COUNT); // Since txCount < DataRepetitionCount, stored data should not be deleted assertNotNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); // Now simulate the onDataSendStatus() callback being received with a higher TxCount value. mUwbSessionManager.onDataSendStatus(TEST_SESSION_ID, STATUS_CODE_DATA_TRANSFER_OK, DATA_SEQUENCE_NUM, DATA_TRANSMISSION_COUNT_3 + 1); // Since txCount = DataRepetitionCount, stored data should removed assertNull(uwbSession.getSendDataInfo(DATA_SEQUENCE_NUM)); } @Test public void stopRanging_sessionStateActive() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for stop ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); assertThat(mTestLooper.nextMessage().what).isEqualTo(3); // SESSION_STOP_RANGING } @Test public void stopRanging_sessionStateIdle() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for stop ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); verify(mUwbSessionNotificationManager).onRangingStopped( eq(uwbSession), eq(UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS)); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void stopRanging_sessionStateError() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); // set up for stop ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_ERROR).when(uwbSession).getSessionState(); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); verify(mUwbSessionNotificationManager).onRangingStopFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_REJECTED)); } @Test public void execStopRanging_success() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbInjector).runTaskOnSingleThreadExecutor( any(), eq(IUwbAdapter.RANGING_SESSION_START_THRESHOLD_MS)); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.LOCAL_API), any()); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void execStopRanging_exception() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenThrow(new IllegalStateException()); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager, never()).onRangingStopped(any(), anyInt()); } @Test public void execStopRanging_nativeFailed() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE).when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager) .onRangingStopFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbMetrics, never()).longRangingStopEvent(eq(uwbSession)); } @Test public void testFiraSessionStoppedDuetoInbandSignal() throws Exception { //Assuming that when session is in active state, //in-band signal is received and session moved IDLE state UwbSession uwbSession = prepareExistingUwbSession(); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_REJECTED); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY), any()); } @Test public void testCCCSessionStoppedDuetoInbandSignal() throws Exception { UwbSession uwbSession = prepareExistingCccUwbSession(); CccRangingStartedParams cccRangingStartedParams = new CccRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_sessionStoppedDuetoInbandSignal( uwbSession, cccRangingStartedParams, CccParams.PROTOCOL_VERSION_1_0); } @Test public void testAliroSessionStoppedDuetoInbandSignal() throws Exception { UwbSession uwbSession = prepareExistingAliroUwbSession(); AliroRangingStartedParams aliroRangingStartedParams = new AliroRangingStartedParams.Builder() .setStartingStsIndex(0) .setUwbTime0(1) .setHopModeKey(0) .setSyncCodeIndex(1) .setRanMultiplier(4) .build(); do_sessionStoppedDuetoInbandSignal( uwbSession, aliroRangingStartedParams, AliroParams.PROTOCOL_VERSION_1_0); } private void do_sessionStoppedDuetoInbandSignal(UwbSession uwbSession, Params rangingStartedParams, ProtocolVersion protocolVersion) throws Exception { // Assuming that when session is in active state, an in-band signal is received and the // session is moved to IDLE state. when(mUwbConfigurationManager.getAppConfigurations( eq(TEST_SESSION_ID), anyString(), any(), any(), eq(TEST_CHIP_ID), eq(protocolVersion))) .thenReturn(new Pair<>(UwbUciConstants.STATUS_CODE_OK, rangingStartedParams)); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_REJECTED); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY), any()); } @Test public void reconfigure_notExistingSession() { int status = mUwbSessionManager.reconfigure(mock(SessionHandle.class), mock(Params.class)); assertThat(status).isEqualTo(UwbUciConstants.STATUS_CODE_ERROR_SESSION_NOT_EXIST); } private FiraRangingReconfigureParams buildReconfigureParams() { return buildReconfigureParams(FiraParams.MULTICAST_LIST_UPDATE_ACTION_ADD); } private FiraRangingReconfigureParams buildReconfigureParams(int action) { FiraRangingReconfigureParams reconfigureParams = new FiraRangingReconfigureParams.Builder() .setAddressList(new UwbAddress[] { UwbAddress.fromBytes(new byte[] { (byte) 0x01, (byte) 0x02 }) }) .setAction(action) .setSubSessionIdList(new int[] { 2 }) .build(); return spy(reconfigureParams); } private FiraRangingReconfigureParams buildReconfigureParamsV2() { return buildReconfigureParamsV2( FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE); } private FiraRangingReconfigureParams buildReconfigureParamsV2(int action) { FiraRangingReconfigureParams reconfigureParams = new FiraRangingReconfigureParams.Builder() .setAddressList(new UwbAddress[] { UwbAddress.fromBytes(new byte[] { (byte) 0x01, (byte) 0x02 }) }) .setAction(action) .setSubSessionIdList(new int[] { 2 }) .setSubSessionKeyList(new byte[] {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3}) .build(); return spy(reconfigureParams); } @Test public void reconfigure_existingSession() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); int status = mUwbSessionManager.reconfigure( uwbSession.getSessionHandle(), buildReconfigureParamsV2()); assertThat(status).isEqualTo(0); assertThat(mTestLooper.nextMessage().what).isEqualTo(4); // SESSION_RECONFIGURE_RANGING } @Test public void execReconfigureAddControlee_success() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParams(); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(1); when(uwbMulticastListUpdateStatus.getControleeUwbAddresses()) .thenReturn(new UwbAddress[] {UWB_DEST_ADDRESS_2}); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_OK }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); // Make sure the original address is still there. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS))) .isTrue(); // Make sure this new address was added. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS_2))) .isTrue(); byte[] dstAddress = getComputedMacAddress(reconfigureParams.getAddressList()[0].toBytes()); verify(mNativeUwbManager).controllerMulticastListUpdate( uwbSession.getSessionId(), reconfigureParams.getAction(), 1, dstAddress, reconfigureParams.getSubSessionIdList(), null, uwbSession.getChipId()); verify(mUwbSessionNotificationManager).onControleeAdded(eq(uwbSession)); verify(mUwbSessionNotificationManager).onRangingReconfigured(eq(uwbSession)); } @Test public void execReconfigureAddControlee_failed() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(FiraParams.MULTICAST_LIST_UPDATE_ACTION_ADD); int status = mUwbSessionManager .reconfigure(uwbSession.getSessionHandle(), reconfigureParams); assertThat(status).isEqualTo(UwbUciConstants.STATUS_CODE_REJECTED); } @Test public void execReconfigureRemoveControleeV1_success() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParams(FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(1); when(uwbMulticastListUpdateStatus.getControleeUwbAddresses()) .thenReturn(new UwbAddress[] {UWB_DEST_ADDRESS}); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_OK }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); // Make sure the address exists in the first place. This should have been set up by // prepareExistingUwbSession assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS))) .isTrue(); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); // Make sure the address was removed. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS))) .isFalse(); byte[] dstAddress = getComputedMacAddress(reconfigureParams.getAddressList()[0].toBytes()); verify(mNativeUwbManager).controllerMulticastListUpdate( uwbSession.getSessionId(), reconfigureParams.getAction(), 1, dstAddress, reconfigureParams.getSubSessionIdList(), null, uwbSession.getChipId()); verify(mUwbSessionNotificationManager).onControleeRemoved(eq(uwbSession), eq(UWB_DEST_ADDRESS), anyInt()); verify(mUwbSessionNotificationManager).onRangingReconfigured(eq(uwbSession)); } @Test public void execReconfigureRemoveControlee_failed() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE); int status = mUwbSessionManager .reconfigure(uwbSession.getSessionHandle(), reconfigureParams); assertThat(status).isEqualTo(UwbUciConstants.STATUS_CODE_REJECTED); } @Test public void execReconfigureAddControleeV2_success() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(1); when(uwbMulticastListUpdateStatus.getControleeUwbAddresses()) .thenReturn(new UwbAddress[] {UWB_DEST_ADDRESS_2}); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_OK }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); // Make sure the original address is still there. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS))) .isTrue(); // Make sure this new address was added. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS_2))) .isTrue(); byte[] dstAddress = getComputedMacAddress(reconfigureParams.getAddressList()[0].toBytes()); verify(mNativeUwbManager).controllerMulticastListUpdate( uwbSession.getSessionId(), reconfigureParams.getAction(), 1, dstAddress, reconfigureParams.getSubSessionIdList(), reconfigureParams.getSubSessionKeyList(), uwbSession.getChipId()); verify(mUwbSessionNotificationManager).onControleeAdded(eq(uwbSession)); verify(mUwbSessionNotificationManager).onRangingReconfigured(eq(uwbSession)); } @Test public void execReconfigureAddControlee_fetchKeysFromSE_V2_success() throws Exception { // When both sessionKey and subSessionKey are not provided from APP, // it will be fetched from SE FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParams(FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(1); when(uwbMulticastListUpdateStatus.getControleeUwbAddresses()) .thenReturn(new UwbAddress[] {UWB_DEST_ADDRESS_2}); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_OK }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); // Make sure the original address is still there. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS))) .isTrue(); // Make sure this new address was added. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS_2))) .isTrue(); byte[] dstAddress = getComputedMacAddress(reconfigureParams.getAddressList()[0].toBytes()); verify(mNativeUwbManager).controllerMulticastListUpdate( uwbSession.getSessionId(), reconfigureParams.getAction(), 1, dstAddress, reconfigureParams.getSubSessionIdList(), reconfigureParams.getSubSessionKeyList(), uwbSession.getChipId()); verify(mUwbSessionNotificationManager).onControleeAdded(eq(uwbSession)); verify(mUwbSessionNotificationManager).onRangingReconfigured(eq(uwbSession)); } @Test public void execReconfigureAddControlee_onlyWithSessionKey_failed() throws Exception { //If sessionKey is only provided from app, reconfigure will be rejected from sessionManager FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParams(FiraParams.P_STS_MULTICAST_LIST_UPDATE_ACTION_ADD_16_BYTE); int status = mUwbSessionManager .reconfigure(uwbSession.getSessionHandle(), reconfigureParams); assertThat(status).isEqualTo(UwbUciConstants.STATUS_CODE_REJECTED); } @Test public void execReconfigureAddControlee_onlyWithSubSessionKey_failed() throws Exception { //If subSessionKeyList is only provided from app, //reconfigure will be rejected from sessionManager FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); int status = mUwbSessionManager .reconfigure(uwbSession.getSessionHandle(), reconfigureParams); assertThat(status).isEqualTo(UwbUciConstants.STATUS_CODE_REJECTED); } @Test public void execReconfigure_nativeUpdateFailed() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); //return status > 0 indicates failure //TBD: update session and address from params UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(status.getNumOfControlee()).thenReturn(1); when(status.getControleeUwbAddresses()).thenReturn( new UwbAddress[] { UWB_DEST_ADDRESS_2 }); when(status.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_FAILED }); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onControleeAddFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager).onRangingReconfigureFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execReconfigure_uwbSessionUpdateMixedSuccess() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(2); when(uwbMulticastListUpdateStatus.getControleeUwbAddresses()).thenReturn( new UwbAddress[] { UWB_DEST_ADDRESS_2, UWB_DEST_ADDRESS_3 }); // One fail, one success when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_FAILED, UwbUciConstants.STATUS_CODE_OK }); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(uwbMulticastListUpdateStatus); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); // Fail callback for the first one. verify(mUwbSessionNotificationManager).onControleeAddFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); // Success callback for the second. verify(mUwbSessionNotificationManager).onControleeAdded(eq(uwbSession)); // Make sure the failed address was not added. assertThat(uwbSession.getControleeList().stream() .anyMatch(e -> e.getUwbAddress().equals(UWB_DEST_ADDRESS_2))) .isFalse(); // Overall reconfigure fail. verify(mUwbSessionNotificationManager).onRangingReconfigureFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execReconfigure_uwbSessionUpdateFailed() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getNumOfControlee()).thenReturn(1); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_FAILED }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onControleeAddFailed(eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbSessionNotificationManager).onRangingReconfigureFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void execReconfigureBlockStriding_success_stop() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); FiraRangingReconfigureParams reconfigureParams = new FiraRangingReconfigureParams.Builder() .setBlockStrideLength(10) .build(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingReconfigured(uwbSession); doReturn(UwbUciConstants.UWB_SESSION_STATE_ACTIVE, UwbUciConstants.UWB_SESSION_STATE_IDLE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.stopRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.stopRanging(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbInjector).runTaskOnSingleThreadExecutor( any(), eq(TEST_RANGING_INTERVAL_MS * 4 * 11)); verify(mUwbSessionNotificationManager) .onRangingStoppedWithApiReasonCode(eq(uwbSession), eq(RangingChangeReason.LOCAL_API), any()); verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession)); } @Test public void execReconfigure_setAppConfigurationsFailed() throws Exception { FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder( (FiraOpenSessionParams) setupFiraParams(FIRA_VERSION_1_1)) .setSessionKey(new byte[]{0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78, 0x5, 0x78}) .setStsConfig(FiraParams.STS_CONFIG_PROVISIONED_FOR_CONTROLEE_INDIVIDUAL_KEY) .build(); UwbSession uwbSession = prepareExistingUwbSession(firaParams); FiraRangingReconfigureParams reconfigureParams = buildReconfigureParamsV2(); UwbMulticastListUpdateStatus status = mock(UwbMulticastListUpdateStatus.class); when(mNativeUwbManager .controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(), any(), anyString())) .thenReturn(status); when(status.getNumOfControlee()).thenReturn(1); UwbMulticastListUpdateStatus uwbMulticastListUpdateStatus = mock(UwbMulticastListUpdateStatus.class); when(uwbMulticastListUpdateStatus.getStatus()).thenReturn( new int[] { UwbUciConstants.STATUS_CODE_OK }); doReturn(uwbMulticastListUpdateStatus).when(uwbSession).getMulticastListUpdateStatus(); when(mUwbConfigurationManager.setAppConfigurations(anyInt(), any(), anyString(), any())) .thenReturn(UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.reconfigure(uwbSession.getSessionHandle(), reconfigureParams); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingReconfigureFailed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); } @Test public void testSetDataTransferPhaseConfig() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_DATA_TRANSFER) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_DATA_TRANSFER, params); byte dtpcmRepetition = 0; byte dataTransferControl = 0; byte dtpmlSize = 2; byte[] slotBitmapBytes = new byte[] { 0x10, 0x20 }; List firaDataTransferPhaseManagementList = new ArrayList<>(); ByteBuffer expectedMacAddressBuf = ByteBuffer.allocate( UwbAddress.SHORT_ADDRESS_BYTE_LENGTH * dtpmlSize); // Setup Phase #1 byte[] macAddressBytes = new byte[]{0x22, 0x11}; UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {(byte) 0x10})); // Setup Phase #2 macAddressBytes = new byte[]{0x44, 0x33}; uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {(byte) 0x20})); FiraDataTransferPhaseConfig firaDataTransferPhaseConfig = new FiraDataTransferPhaseConfig.Builder() .setDtpcmRepetition((byte) dtpcmRepetition) .setMacAddressMode((byte) 0) .setSlotBitmapSize((byte) 0) .setDataTransferPhaseManagementList(firaDataTransferPhaseManagementList) .build(); byte[] expectedMacAddressBytes = expectedMacAddressBuf.array(); when(mNativeUwbManager.setDataTransferPhaseConfig(eq(TEST_SESSION_ID), eq(dtpcmRepetition), eq(dataTransferControl), eq(dtpmlSize), eq(expectedMacAddressBytes), eq(slotBitmapBytes), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.setDataTransferPhaseConfig( uwbSession.getSessionHandle(), firaDataTransferPhaseConfig.toBundle()); mTestLooper.dispatchNext(); verify(mNativeUwbManager).setDataTransferPhaseConfig(TEST_SESSION_ID, dtpcmRepetition, dataTransferControl, dtpmlSize, expectedMacAddressBytes, slotBitmapBytes, TEST_CHIP_ID); } @Test public void testSetDataTransferPhaseConfigNonZeroslotBitMap() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_AND_IN_BAND_DATA) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_AND_IN_BAND_DATA, params); byte dtpcmRepetition = 0; byte dataTransferControl = 4; byte dtpmlSize = 2; byte[] slotBitmapBytes = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, (byte) 0x80 }; List firaDataTransferPhaseManagementList = new ArrayList<>(); ByteBuffer expectedMacAddressBuf = ByteBuffer.allocate( UwbAddress.SHORT_ADDRESS_BYTE_LENGTH * dtpmlSize); // Setup Phase #1 byte[] macAddressBytes = new byte[]{0x22, 0x11}; UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {0x10, 0x20, 0x30, 0x40})); // Setup Phase #2 macAddressBytes = new byte[]{0x44, 0x33}; uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {0x50, 0x60, 0x70, (byte) 0x80})); FiraDataTransferPhaseConfig firaDataTransferPhaseConfig = new FiraDataTransferPhaseConfig.Builder() .setDtpcmRepetition((byte) dtpcmRepetition) .setMacAddressMode((byte) 0) .setSlotBitmapSize((byte) 2) .setDataTransferPhaseManagementList(firaDataTransferPhaseManagementList) .build(); byte[] expectedMacAddressBytes = expectedMacAddressBuf.array(); when(mNativeUwbManager.setDataTransferPhaseConfig(eq(TEST_SESSION_ID), eq(dtpcmRepetition), eq(dataTransferControl), eq(dtpmlSize), eq(expectedMacAddressBytes), eq(slotBitmapBytes), eq(TEST_CHIP_ID))) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.setDataTransferPhaseConfig( uwbSession.getSessionHandle(), firaDataTransferPhaseConfig.toBundle()); mTestLooper.dispatchNext(); verify(mNativeUwbManager).setDataTransferPhaseConfig(TEST_SESSION_ID, dtpcmRepetition, dataTransferControl, dtpmlSize, expectedMacAddressBytes, slotBitmapBytes, TEST_CHIP_ID); } @Test public void testSetDataTransferPhaseConfigFailedDueToInvalidSessionType() throws Exception { byte dtpcmRepetition = 0; byte dataTransferControl = 0; byte dtpmlSize = 2; byte[] slotBitmapBytes = new byte[] { 0x10, 0x20 }; /** By default SESSION_TYPE_RANGING is used, so testcase is expected to * fail due to Invalid session type for data transfer phase config */ UwbSession uwbSession = prepareExistingUwbSessionActive(); List firaDataTransferPhaseManagementList = new ArrayList<>(); ByteBuffer expectedMacAddressBuf = ByteBuffer.allocate( UwbAddress.SHORT_ADDRESS_BYTE_LENGTH * dtpmlSize); // Setup Phase #1 byte[] macAddressBytes = new byte[]{0x22, 0x11}; UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {(byte) 0x10})); // Setup Phase #2 macAddressBytes = new byte[]{0x44, 0x33}; uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {(byte) 0x20, 0x30})); //Invalid slot bit map FiraDataTransferPhaseConfig firaDataTransferPhaseConfig = new FiraDataTransferPhaseConfig.Builder() .setDtpcmRepetition((byte) dtpcmRepetition) .setMacAddressMode((byte) 0) .setSlotBitmapSize((byte) 1) .setDataTransferPhaseManagementList(firaDataTransferPhaseManagementList) .build(); mUwbSessionManager.setDataTransferPhaseConfig( uwbSession.getSessionHandle(), firaDataTransferPhaseConfig.toBundle()); mTestLooper.dispatchNext(); byte[] expectedMacAddressBytes = expectedMacAddressBuf.array(); verify(mNativeUwbManager, never()).setDataTransferPhaseConfig(TEST_SESSION_ID, dtpcmRepetition, dataTransferControl, dtpmlSize, expectedMacAddressBytes, slotBitmapBytes, TEST_CHIP_ID); } @Test public void testSetDataTransferPhaseConfigFailedDueToInvalidList() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); byte dtpcmRepetition = 0; byte dataTransferControl = 0; byte dtpmlSize = 2; byte[] slotBitmapBytes = new byte[] { 0x10, 0x20 }; List firaDataTransferPhaseManagementList = new ArrayList<>(); ByteBuffer expectedMacAddressBuf = ByteBuffer.allocate( UwbAddress.SHORT_ADDRESS_BYTE_LENGTH); // Setup Phase #1 byte[] macAddressBytes = new byte[]{0x22, 0x11}; UwbAddress uwbAddress = UwbAddress.fromBytes(macAddressBytes); expectedMacAddressBuf.put(getComputedMacAddress(macAddressBytes)); firaDataTransferPhaseManagementList.add( new FiraDataTransferPhaseConfig.FiraDataTransferPhaseManagementList( uwbAddress, new byte[] {(byte) 0x10})); // Size of dtpml-Size is 2 but only one set of configs are provided FiraDataTransferPhaseConfig firaDataTransferPhaseConfig = new FiraDataTransferPhaseConfig.Builder() .setDtpcmRepetition((byte) dtpcmRepetition) .setMacAddressMode((byte) 0) .setSlotBitmapSize((byte) 1) .setDataTransferPhaseManagementList(firaDataTransferPhaseManagementList) .build(); mUwbSessionManager.setDataTransferPhaseConfig( uwbSession.getSessionHandle(), firaDataTransferPhaseConfig.toBundle()); mTestLooper.dispatchNext(); byte[] expectedMacAddressBytes = expectedMacAddressBuf.array(); verify(mNativeUwbManager, never()).setDataTransferPhaseConfig(TEST_SESSION_ID, dtpcmRepetition, dataTransferControl, dtpmlSize, expectedMacAddressBytes, slotBitmapBytes, TEST_CHIP_ID); } @Test public void testQueryDataSize() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.queryMaxDataSizeBytes( eq(uwbSession.getSessionId()), eq(TEST_CHIP_ID))) .thenReturn(MAX_DATA_SIZE); assertThat(mUwbSessionManager.queryMaxDataSizeBytes(uwbSession.getSessionHandle())) .isEqualTo(MAX_DATA_SIZE); } @Test public void testQueryDataSize_whenUwbSessionDoesNotExist() throws Exception { SessionHandle mockSessionHandle = mock(SessionHandle.class); assertThrows(IllegalStateException.class, () -> mUwbSessionManager.queryMaxDataSizeBytes(mockSessionHandle)); } @Test public void testReferenceTimeBase() throws Exception { Params refParams = setupFiraParams(new FiraProtocolVersion(2, 0)); FiraOpenSessionParams refFiraParams = new FiraOpenSessionParams.Builder((FiraOpenSessionParams) refParams) .setSessionId(TEST_SESSION_ID) .build(); UwbSession refUwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE, refFiraParams); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, refUwbSession.getSessionHandle(), TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, refUwbSession.getParams(), refUwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); when(mNativeUwbManager.getSessionToken(eq(TEST_SESSION_ID), anyString())) .thenReturn(REFERENCE_SESSION_HANDLE); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(refUwbSession).getSessionState(); mTestLooper.dispatchAll(); Params params = setupFiraParams(new FiraProtocolVersion(2, 0)); FiraOpenSessionParams firaParams = new FiraOpenSessionParams.Builder((FiraOpenSessionParams) params) .setSessionId(TEST_SESSION_ID_2) .setSessionTimeBase(1, TEST_SESSION_ID, 200) .build(); UwbSession uwbSession = setUpUwbSessionForExecution(ATTRIBUTION_SOURCE, firaParams); when(mNativeUwbManager.initSession(anyInt(), anyByte(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); doReturn(UwbUciConstants.UWB_SESSION_STATE_INIT, UwbUciConstants.UWB_SESSION_STATE_IDLE).when(uwbSession).getSessionState(); mUwbSessionManager.initSession(ATTRIBUTION_SOURCE, uwbSession.getSessionHandle(), TEST_SESSION_ID_2, TEST_SESSION_TYPE, FiraParams.PROTOCOL_NAME, uwbSession.getParams(), uwbSession.getIUwbRangingCallbacks(), TEST_CHIP_ID); mTestLooper.dispatchAll(); verify(uwbSession).updateFiraParamsForSessionTimeBase(REFERENCE_SESSION_HANDLE); } @Test public void testsetHybridSessionControllerConfiguration_shortMacAddress() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_IN_BAND_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_IN_BAND_DATA_PHASE, params); byte messageControl = 0; int noOfPhases = 2; byte phaseParticipation = 0; byte [] updateTime = new byte[8]; short startSlotIndex1 = 0x01, endSlotIndex1 = 0x34; short startSlotIndex2 = 0x37, endSlotIndex2 = 0x64; // Setup the expected byte-array for the Hybrid configuration. ByteBuffer expectedHybridConfigBytes = ByteBuffer.allocate(noOfPhases * UWB_HUS_CONTROLLER_PHASE_LIST_SHORT_MAC_ADDRESS_SIZE); expectedHybridConfigBytes.order(ByteOrder.LITTLE_ENDIAN); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.putShort(startSlotIndex1); expectedHybridConfigBytes.putShort(endSlotIndex1); expectedHybridConfigBytes.put(phaseParticipation); expectedHybridConfigBytes.put(getComputedMacAddress(UWB_DEST_ADDRESS.toBytes())); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.putShort(startSlotIndex2); expectedHybridConfigBytes.putShort(endSlotIndex2); expectedHybridConfigBytes.put(phaseParticipation); expectedHybridConfigBytes.put(getComputedMacAddress(UWB_DEST_ADDRESS_2.toBytes())); when(mNativeUwbManager.setHybridSessionControllerConfiguration( anyInt(), anyByte(), anyInt(), any(), any(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Invoke the method that triggers the 'setHybridSessionControllerConfiguration' mUwbSessionManager.setHybridSessionControllerConfiguration( uwbSession.getSessionHandle(), mHybridControllerParams.toBundle()); mTestLooper.dispatchAll(); verify(mNativeUwbManager).setHybridSessionControllerConfiguration( uwbSession.getSessionId(), messageControl, noOfPhases, updateTime, expectedHybridConfigBytes.array(), uwbSession.getChipId()); } @Test public void testsetHybridSessionControllerConfiguration_extendedMacAddress() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_ONLY_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_ONLY_PHASE, params); byte[] updateTime = new byte[8]; int noOfPhases = 2; short startSlotIndex1 = 0x01, endSlotIndex1 = 0x34; short startSlotIndex2 = 0x37, endSlotIndex2 = 0x64; byte messageControl = 1; byte phaseParticipation = 0; UwbAddress uwbAddress1 = UwbAddress.fromBytes(new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x56, 0x57, 0x66 }); UwbAddress uwbAddress2 = UwbAddress.fromBytes(new byte[] { 0x22, 0x22, 0x33, 0x44, 0x55, 0x56, 0x57, 0x66 }); FiraHybridSessionControllerConfig hybridParams = new FiraHybridSessionControllerConfig.Builder() .setNumberOfPhases(noOfPhases) .setUpdateTime(updateTime) .setMacAddressMode((byte) 1) .addPhaseList( new FiraHybridSessionControllerConfig.FiraHybridSessionPhaseList( SESSION_HANDLE.getId(), startSlotIndex1, endSlotIndex1, phaseParticipation, uwbAddress1)) .addPhaseList( new FiraHybridSessionControllerConfig.FiraHybridSessionPhaseList( SESSION_HANDLE_2.getId(), startSlotIndex2, endSlotIndex2, phaseParticipation, uwbAddress2)) .build(); /* Setup the expected byte-array for the Hybrid configuration. */ ByteBuffer expectedHybridConfigBytes = ByteBuffer.allocate(noOfPhases * UWB_HUS_CONTROLLER_PHASE_LIST_EXTENDED_MAC_ADDRESS_SIZE); expectedHybridConfigBytes.order(ByteOrder.LITTLE_ENDIAN); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.putShort(startSlotIndex1); expectedHybridConfigBytes.putShort(endSlotIndex1); expectedHybridConfigBytes.put(phaseParticipation); expectedHybridConfigBytes.put(getComputedMacAddress(uwbAddress1.toBytes())); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.putShort(startSlotIndex2); expectedHybridConfigBytes.putShort(endSlotIndex2); expectedHybridConfigBytes.put(phaseParticipation); expectedHybridConfigBytes.put(getComputedMacAddress(uwbAddress2.toBytes())); when(mNativeUwbManager.setHybridSessionControllerConfiguration( anyInt(), anyByte(), anyInt(), any(), any(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Invoke the method that triggers the 'setHybridSessionControllerConfiguration' mUwbSessionManager.setHybridSessionControllerConfiguration( uwbSession.getSessionHandle(), hybridParams.toBundle()); mTestLooper.dispatchAll(); verify(mNativeUwbManager).setHybridSessionControllerConfiguration( uwbSession.getSessionId(), messageControl, noOfPhases, updateTime, expectedHybridConfigBytes.array(), uwbSession.getChipId()); } @Test public void testsetHybridSessionControllerWithInvalidInvalidSessionType() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING, params); // Expected to fail due to invalid session type mUwbSessionManager.setHybridSessionControllerConfiguration( uwbSession.getSessionHandle(), mHybridControllerParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControllerConfigurationFailed( any(), anyInt()); } @Test public void testsetHybridSessionControllerWithInvalidScheduledMode() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.TIME_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE, params); // Expected to fail due to invalid scheduled mode mUwbSessionManager.setHybridSessionControllerConfiguration( uwbSession.getSessionHandle(), mHybridControllerParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControllerConfigurationFailed( any(), anyInt()); } @Test public void testsetHybridSessionControllerWithInvalidDeviceType() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE, params); // Expected to fail due to invalid device type(controlee) mUwbSessionManager.setHybridSessionControllerConfiguration( uwbSession.getSessionHandle(), mHybridControllerParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControllerConfigurationFailed( any(), anyInt()); } @Test public void testsetHybridSessionControllerConfiguration_whenUwbSessionDoesNotExist() throws Exception { SessionHandle mockSessionHandle = mock(SessionHandle.class); assertThrows(IllegalStateException.class, () -> mUwbSessionManager.setHybridSessionControllerConfiguration(mockSessionHandle, mock(PersistableBundle.class))); } @Test public void testsetHybridSessionControleeConfiguration_whenUwbSessionDoesNotExist() throws Exception { SessionHandle mockSessionHandle = mock(SessionHandle.class); assertThrows(IllegalStateException.class, () -> mUwbSessionManager.setHybridSessionControleeConfiguration(mockSessionHandle, mock(PersistableBundle.class))); } @Test public void testsetHybridSessionControleeConfiguration() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE, params); int noOfPhases = 2; byte phaseParticipation = 0; // Setup the expected byte-array for the Hybrid configuration. ByteBuffer expectedHybridConfigBytes = ByteBuffer.allocate(noOfPhases * UWB_HUS_CONTROLEE_PHASE_LIST_SIZE); expectedHybridConfigBytes.order(ByteOrder.LITTLE_ENDIAN); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.put(phaseParticipation); expectedHybridConfigBytes.putInt(0); //SessionToken expectedHybridConfigBytes.put(phaseParticipation); when(mNativeUwbManager.setHybridSessionControleeConfiguration( anyInt(), anyInt(), any(), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Invoke the method that triggers the 'setHybridSessionControllerConfiguration' mUwbSessionManager.setHybridSessionControleeConfiguration( uwbSession.getSessionHandle(), mHybridControleeParams.toBundle()); mTestLooper.dispatchAll(); verify(mNativeUwbManager).setHybridSessionControleeConfiguration( uwbSession.getSessionId(), noOfPhases, expectedHybridConfigBytes.array(), uwbSession.getChipId()); } @Test public void testsetHybridSessionControleeWithInvalidInvalidSessionType() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_DATA_TRANSFER) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_DATA_TRANSFER, params); // Expected to fail due to invalid session type mUwbSessionManager.setHybridSessionControleeConfiguration( uwbSession.getSessionHandle(), mHybridControleeParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControleeConfigurationFailed( any(), anyInt()); } @Test public void testsetHybridSessionControleeWithInvalidScheduledMode() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLEE) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.TIME_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE, params); // Expected to fail due to invalid scheduded mode mUwbSessionManager.setHybridSessionControleeConfiguration( uwbSession.getSessionHandle(), mHybridControleeParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControleeConfigurationFailed( any(), anyInt()); } @Test public void testsetHybridSessionControleeWithInvalidDeviceType() throws Exception { FiraOpenSessionParams params = new FiraOpenSessionParams.Builder() .setDeviceAddress(UwbAddress.fromBytes(new byte[] {(byte) 0x01, (byte) 0x02 })) .setVendorId(new byte[] { (byte) 0x00, (byte) 0x01 }) .setStaticStsIV(new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 }) .setDestAddressList(Arrays.asList( UWB_DEST_ADDRESS)) .setProtocolVersion(new FiraProtocolVersion(1, 0)) .setSessionId(10) .setSessionType(FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE) .setDeviceType(FiraParams.RANGING_DEVICE_TYPE_CONTROLLER) .setDeviceRole(FiraParams.RANGING_DEVICE_ROLE_INITIATOR) .setMultiNodeMode(FiraParams.MULTI_NODE_MODE_UNICAST) .setRangingIntervalMs(TEST_RANGING_INTERVAL_MS) .setScheduledMode(FiraParams.HYBRID_SCHEDULED_RANGING) .setDataRepetitionCount(0) .build(); UwbSession uwbSession = prepareExistingUwbSessionWithSessionType( (byte) FiraParams.SESSION_TYPE_RANGING_WITH_DATA_PHASE, params); // Expected to fail due to invalid device type(controller) mUwbSessionManager.setHybridSessionControleeConfiguration( uwbSession.getSessionHandle(), mHybridControleeParams.toBundle()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onHybridSessionControleeConfigurationFailed( any(), anyInt()); } @Test public void deInitSession_notExistedSession() { doReturn(false).when(mUwbSessionManager).isExistedSession(any()); mUwbSessionManager.deInitSession(mock(SessionHandle.class)); verify(mUwbSessionManager, never()).getSessionId(any()); assertThat(mTestLooper.nextMessage()).isNull(); } @Test public void deInitSession_success() { doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); UwbSession mockUwbSession = mock(UwbSession.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); mUwbSessionManager.mSessionTable.put(mockSessionHandle, mockUwbSession); mUwbSessionManager.deInitSession(mockSessionHandle); assertThat(mTestLooper.nextMessage().what).isEqualTo(5); // SESSION_DEINIT verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void deInitSession_success_afterOwrAoaMeasurement() { UwbSession mockUwbSession = mock(UwbSession.class); SessionHandle mockSessionHandle = mock(SessionHandle.class); mUwbSessionManager.mSessionTable.put(mockSessionHandle, mockUwbSession); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); when(mockUwbSession.getSessionHandle()).thenReturn(mockSessionHandle); doReturn(mockUwbSession).when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); // Setup the UwbSession to have the peer device's MacAddress stored (which happens when // a valid RANGE_DATA_NTF with an OWR AoA Measurement is received). doReturn(Set.of(PEER_EXTENDED_MAC_ADDRESS_LONG)).when(mockUwbSession) .getRemoteMacAddressList(); // Call deInitSession(). IBinder mockBinder = mock(IBinder.class); doReturn(mockBinder).when(mockUwbSession).getBinder(); doReturn(FiraParams.PROTOCOL_NAME).when(mockUwbSession).getProtocolName(); doReturn(null).when(mockUwbSession).getAnyNonPrivilegedAppInAttributionSource(); doReturn(true).when(mUwbSessionManager).isExistedSession(any()); doReturn(TEST_SESSION_ID).when(mUwbSessionManager).getSessionId(any()); doReturn(TEST_SESSION_ID).when(mockUwbSession).getSessionId(); mUwbSessionManager.deInitSession(mockSessionHandle); mTestLooper.dispatchNext(); verify(mUwbAdvertiseManager).removeAdvertiseTarget(PEER_EXTENDED_MAC_ADDRESS_LONG); } @Test public void execDeInitSession() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); assertThat(mTestLooper.nextMessage().what).isEqualTo(5); // SESSION_DEINIT } @Test public void execDeInitSession_success() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingClosed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void execDeInitSession_failed() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingClosed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); verify(mUwbAdvertiseManager, never()).removeAdvertiseTarget(isA(Long.class)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void execDeInitSession_multipleTimes() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); // Call deInitSession() twice on the same UWB Session, and then proceed to dispatch the two // messages for both the calls. The second message should not have any effect, and silently // stop processing. mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); mUwbSessionManager.deInitSession(uwbSession.getSessionHandle()); mTestLooper.dispatchNext(); mTestLooper.dispatchNext(); // Verify the DeInit steps. verify(mUwbSessionNotificationManager, times(1)).onRangingClosed( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); verifyZeroInteractions(mUwbAdvertiseManager); } @Test public void deinitAllSession() { UwbSession mockUwbSession1 = mock(UwbSession.class); SessionHandle mockSessionHandle1 = mock(SessionHandle.class); when(mockUwbSession1.getSessionId()).thenReturn(TEST_SESSION_ID); when(mockUwbSession1.getBinder()).thenReturn(mock(IBinder.class)); when(mockUwbSession1.getSessionId()).thenReturn(TEST_SESSION_ID); when(mockUwbSession1.getProtocolName()).thenReturn(FiraParams.PROTOCOL_NAME); when(mockUwbSession1.getSessionHandle()).thenReturn(mockSessionHandle1); mUwbSessionManager.mSessionTable.put(mockSessionHandle1, mockUwbSession1); UwbSession mockUwbSession2 = mock(UwbSession.class); SessionHandle mockSessionHandle2 = mock(SessionHandle.class); when(mockUwbSession2.getBinder()).thenReturn(mock(IBinder.class)); when(mockUwbSession2.getSessionId()).thenReturn(TEST_SESSION_ID + 100); when(mockUwbSession2.getProtocolName()).thenReturn(FiraParams.PROTOCOL_NAME); when(mockUwbSession2.getSessionHandle()).thenReturn(mockSessionHandle2); mUwbSessionManager.mSessionTable.put(mockSessionHandle2, mockUwbSession2); mUwbSessionManager.deinitAllSession(); verify(mUwbSessionNotificationManager, times(2)) .onRangingClosedWithApiReasonCode(any(), eq(RangingChangeReason.SYSTEM_POLICY)); verify(mUwbSessionManager, times(2)).removeSession(any()); // TODO: enable it when the deviceReset is enabled. // verify(mNativeUwbManager).deviceReset(eq(UwbUciConstants.UWBS_RESET)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); } @Test public void onSessionStatusNotification_session_deinit() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.onSessionStatusNotificationReceived( uwbSession.getSessionId(), SESSION_TOKEN, UwbUciConstants.UWB_SESSION_STATE_DEINIT, UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingClosedWithApiReasonCode( eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); } @Test public void onSessionStatusNotification_session_deinit_after_close() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.deinitAllSession(); verify(mUwbSessionNotificationManager).onRangingClosedWithApiReasonCode( eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); // Ignore the stale deinit mUwbSessionManager.handleOnDeInit(uwbSession); verifyNoMoreInteractions(mUwbSessionNotificationManager); } @Test public void onSessionStatusNotification_session_deinit_owrAoa() throws Exception { Params firaParams = setupFiraParams( RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT)); UwbSession uwbSession = prepareExistingUwbSession(firaParams); UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData( RANGING_MEASUREMENT_TYPE_OWR_AOA, MAC_ADDRESSING_MODE_EXTENDED, UwbUciConstants.STATUS_CODE_OK); // First call onDataReceived() to get the application payload data. when(mDeviceConfigFacade.getRxDataMaxPacketsToStore()) .thenReturn(MAX_RX_DATA_PACKETS_TO_STORE); mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK, DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS, DATA_PAYLOAD); // Next call onRangeDataNotificationReceived() to process the RANGE_DATA_NTF. Setup // isPointedTarget() to return "false", as in that scenario the stored AdvertiseTarget // is not removed. when(mUwbAdvertiseManager.isPointedTarget(PEER_EXTENDED_MAC_ADDRESS)).thenReturn(false); mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData); verify(mUwbAdvertiseManager).updateAdvertiseTarget(uwbRangingData.mRangingOwrAoaMeasure); verify(mUwbAdvertiseManager).isPointedTarget(PEER_EXTENDED_MAC_ADDRESS); // Now call onSessionStatusNotificationReceived() on the same UwbSession, and verify that // removeAdvertiseTarget() is called to remove any stored OwR AoA Measurement(s). when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.onSessionStatusNotificationReceived( uwbSession.getSessionId(), SESSION_TOKEN, UwbUciConstants.UWB_SESSION_STATE_DEINIT, UwbUciConstants.REASON_STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS); mTestLooper.dispatchNext(); verify(mUwbSessionNotificationManager).onRangingClosedWithApiReasonCode( eq(uwbSession), eq(RangingChangeReason.SYSTEM_POLICY)); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); verify(mUwbAdvertiseManager).removeAdvertiseTarget(isA(Long.class)); } @Test public void testHandleClientDeath() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); when(mNativeUwbManager.deInitSession(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED); uwbSession.binderDied(); verify(mUwbMetrics).logRangingCloseEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED)); assertThat(mUwbSessionManager.getSessionCount()).isEqualTo(0); assertThat(mUwbSessionManager.getAliroSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getCccSessionCount()).isEqualTo(0L); assertThat(mUwbSessionManager.getFiraSessionCount()).isEqualTo(0L); } @Test public void testDtTagRangingRoundsUpdate() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); byte[] indices = {1, 2}; DtTagUpdateRangingRoundsStatus status = new DtTagUpdateRangingRoundsStatus(0, indices.length, indices); PersistableBundle bundle = new DlTDoARangingRoundsUpdate.Builder() .setSessionId(uwbSession.getSessionId()) .setNoOfRangingRounds(indices.length) .setRangingRoundIndexes(indices) .build() .toBundle(); when(mNativeUwbManager.sessionUpdateDtTagRangingRounds(anyInt(), anyInt(), any(), anyString())).thenReturn(status); mUwbSessionManager.rangingRoundsUpdateDtTag(uwbSession.getSessionHandle(), bundle); mTestLooper.dispatchAll(); verify(mNativeUwbManager).sessionUpdateDtTagRangingRounds(uwbSession.getSessionId(), indices.length, indices, uwbSession.getChipId()); verify(mUwbSessionNotificationManager).onRangingRoundsUpdateStatus(any(), any()); } @Test public void onDataTransferPhaseConfigNotificationReceived() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(); //successfully setting the configuration mUwbSessionManager.onDataTransferPhaseConfigNotificationReceived(uwbSession.getSessionId(), UwbUciConstants.STATUS_CODE_DATA_TRANSFER_PHASE_CONFIG_DTPCM_CONFIG_SUCCESS); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager) .onDataTransferPhaseConfigured( isA(UwbSession.class), eq(UwbUciConstants.STATUS_CODE_DATA_TRANSFER_PHASE_CONFIG_DTPCM_CONFIG_SUCCESS)); //failed to set the configuration mUwbSessionManager.onDataTransferPhaseConfigNotificationReceived(uwbSession.getSessionId(), UwbUciConstants .STATUS_CODE_DATA_TRANSFER_PHASE_CONFIG_ERROR_DUPLICATE_SLOT_ASSIGNMENT); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onDataTransferPhaseConfigFailed( isA(UwbSession.class), eq(UwbUciConstants.STATUS_CODE_DATA_TRANSFER_PHASE_CONFIG_ERROR_DUPLICATE_SLOT_ASSIGNMENT)); } @Test public void onRadarDataMessageReceivedWithValidUwbSession() { UwbRadarData uwbRadarData = UwbTestUtils.generateUwbRadarData( RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES, UwbUciConstants.STATUS_CODE_OK); UwbSession mockUwbSession = mock(UwbSession.class); when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class)); doReturn(mockUwbSession) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onRadarDataMessageReceived(uwbRadarData); verify(mUwbSessionNotificationManager) .onRadarDataMessageReceived(eq(mockUwbSession), eq(uwbRadarData)); } @Test public void onRadarDataMessageReceivedWithInvalidSession() { UwbRadarData uwbRadarData = UwbTestUtils.generateUwbRadarData( RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES, UwbUciConstants.STATUS_CODE_OK); doReturn(null) .when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID)); mUwbSessionManager.onRadarDataMessageReceived(uwbRadarData); verify(mUwbSessionNotificationManager, never()) .onRadarDataMessageReceived(any(), eq(uwbRadarData)); } @Test public void execStartRanging_onRadarDataMessage() throws Exception { UwbSession uwbSession = prepareExistingUwbSession(setupRadarParams()); // set up for start ranging doReturn(UwbUciConstants.UWB_SESSION_STATE_IDLE, UwbUciConstants.UWB_SESSION_STATE_ACTIVE) .when(uwbSession).getSessionState(); when(mNativeUwbManager.startRanging(eq(TEST_SESSION_ID), anyString())) .thenReturn((byte) UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.startRanging( uwbSession.getSessionHandle(), uwbSession.getParams()); mTestLooper.dispatchAll(); verify(mUwbSessionNotificationManager).onRangingStarted(eq(uwbSession), any()); verify(mUwbMetrics).longRangingStartEvent( eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_OK)); // Now send a radar data notification. UwbRadarData uwbRadarData = UwbTestUtils.generateUwbRadarData( RADAR_DATA_TYPE_RADAR_SWEEP_SAMPLES, UwbUciConstants.STATUS_CODE_OK); mUwbSessionManager.onRadarDataMessageReceived(uwbRadarData); verify(mUwbSessionNotificationManager) .onRadarDataMessageReceived(uwbSession, uwbRadarData); } private UwbSessionManager.ReceivedDataInfo buildReceivedDataInfo(long macAddress) { return buildReceivedDataInfo(macAddress, DATA_SEQUENCE_NUM); } private UwbSessionManager.ReceivedDataInfo buildReceivedDataInfo( long macAddress, long sequenceNum) { UwbSessionManager.ReceivedDataInfo info = new UwbSessionManager.ReceivedDataInfo(); info.sessionId = TEST_SESSION_ID; info.status = STATUS_CODE_OK; info.sequenceNum = sequenceNum; info.address = macAddress; info.payload = DATA_PAYLOAD; return info; } private static byte[] getComputedMacAddress(byte[] address) { if (!SdkLevel.isAtLeastU()) { return TlvUtil.getReverseBytes(address); } return address; } }