blob: 1668ba5d92c1d43c69dc693eb321776a0e50c8e1 [file] [log] [blame]
/*
* 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.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_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_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_REPETITION_OK;
import static com.google.common.truth.Truth.assertThat;
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 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.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.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.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.UwbMulticastListUpdateStatus;
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.google.uwb.support.base.Params;
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.CccSpecificationParams;
import com.google.uwb.support.ccc.CccStartRangingParams;
import com.google.uwb.support.dltdoa.DlTDoARangingRoundsUpdate;
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 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.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.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_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 byte DATA_SEQUENCE_NUM = 0;
private static final byte DATA_SEQUENCE_NUM_1 = 2;
private static final int SOURCE_END_POINT = 100;
private static final int DEST_END_POINT = 200;
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();
@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 CccSpecificationParams mCccSpecificationParams;
@Mock
private UwbMultichipData mUwbMultichipData;
private TestLooper mTestLooper = new TestLooper();
private UwbSessionManager mUwbSessionManager;
@Captor
private ArgumentCaptor<OnUidImportanceListener> 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()
.setCccSpecificationParams(mCccSpecificationParams)
.setFiraSpecificationParams(
new FiraSpecificationParams.Builder()
.setSupportedChannels(List.of(9))
.setRangeDataNtfConfigCapabilities(
EnumSet.of(
HAS_RANGE_DATA_NTF_CONFIG_DISABLE,
HAS_RANGE_DATA_NTF_CONFIG_ENABLE))
.build());
when(mUwbServiceCore.getCachedSpecificationParams(any())).thenReturn(
mSpecificationParamsBuilder.build());
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() {
UwbSession mockUwbSession = mock(UwbSession.class);
when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class));
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, SOURCE_END_POINT, DEST_END_POINT,
DATA_PAYLOAD);
verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class));
verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK));
}
@Test
public void onDataReceived_unsupportedMacAddressLength() {
UwbSession mockUwbSession = mock(UwbSession.class);
when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class));
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, SOURCE_END_POINT, DEST_END_POINT,
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() {
UwbSession mockUwbSession = mock(UwbSession.class);
when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class));
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, SOURCE_END_POINT,
DEST_END_POINT, DATA_PAYLOAD);
verify(mockUwbSession).addReceivedDataInfo(isA(UwbSessionManager.ReceivedDataInfo.class));
verify(mUwbMetrics).logDataRx(eq(mockUwbSession), eq(UwbUciConstants.STATUS_CODE_OK));
}
@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));
verify(mUwbMetrics).logRangingResult(anyInt(), 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));
verify(mUwbMetrics, never()).logRangingResult(anyInt(), 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));
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, SOURCE_END_POINT, DEST_END_POINT,
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).logRangingResult(anyInt(), eq(uwbRangingData));
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));
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,
SOURCE_END_POINT, DEST_END_POINT, 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).logRangingResult(anyInt(), eq(uwbRangingData));
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));
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, SOURCE_END_POINT, DEST_END_POINT,
DATA_PAYLOAD);
mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK,
DATA_SEQUENCE_NUM_1, PEER_EXTENDED_MAC_ADDRESS, SOURCE_END_POINT, DEST_END_POINT,
DATA_PAYLOAD);
mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK,
DATA_SEQUENCE_NUM, PEER_EXTENDED_MAC_ADDRESS_2, SOURCE_END_POINT, DEST_END_POINT,
DATA_PAYLOAD);
mUwbSessionManager.onDataReceived(TEST_SESSION_ID, UwbUciConstants.STATUS_CODE_OK,
DATA_SEQUENCE_NUM_1, PEER_EXTENDED_MAC_ADDRESS_2, SOURCE_END_POINT, DEST_END_POINT,
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).logRangingResult(anyInt(), eq(uwbRangingData1));
verify(mUwbMetrics).logRangingResult(anyInt(), eq(uwbRangingData2));
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));
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,
SOURCE_END_POINT, DEST_END_POINT, 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);
verify(mUwbMetrics).logRangingResult(anyInt(), eq(uwbRangingData));
}
@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, SOURCE_END_POINT, DEST_END_POINT,
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));
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, SOURCE_END_POINT, DEST_END_POINT,
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));
verify(mUwbMetrics).logRangingResult(anyInt(), 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));
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, SOURCE_END_POINT, DEST_END_POINT,
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));
verify(mUwbMetrics).logRangingResult(anyInt(), 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));
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, SOURCE_END_POINT, DEST_END_POINT,
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));
verify(mUwbMetrics).logRangingResult(anyInt(), 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));
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);
verify(mUwbMetrics).logRangingResult(anyInt(), eq(uwbRangingData));
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));
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, SOURCE_END_POINT, DEST_END_POINT,
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);
verify(mUwbMetrics).logRangingResult(anyInt(), eq(uwbRangingData));
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));
doReturn(mockUwbSession)
.when(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID));
UwbSession mockUwbSession2 = mock(UwbSession.class);
when(mockUwbSession2.getWaitObj()).thenReturn(mock(WaitObj.class));
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, SOURCE_END_POINT, DEST_END_POINT,
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);
verify(mUwbMetrics).logRangingResult(anyInt(), eq(uwbRangingData));
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));
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, SOURCE_END_POINT, DEST_END_POINT,
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(mUwbMetrics).logRangingResult(anyInt(), 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));
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,
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,
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 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).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).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()))
.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());
}
@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);
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);
// 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).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_currentSessionStateActive() {
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_currentSessiionStateInvalid() {
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<Integer> 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) {
// 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);
Params params = setupFiraParams();
UwbSession uwbSession = spy(
mUwbSessionManager.new UwbSession(attributionSource, mockSessionHandle,
TEST_SESSION_ID, TEST_SESSION_TYPE, FiraParams.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 Params setupFiraParams() {
return setupFiraParams(FiraParams.RANGING_DEVICE_ROLE_INITIATOR, Optional.empty());
}
private Params setupFiraParams(int deviceRole, Optional<Integer> rangingRoundUsageOptional) {
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(new FiraProtocolVersion(1, 0))
.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();
}
private UwbSession setUpCccUwbSessionForExecution() 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);
Params params = 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();
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;
}
@Test
public void openRanging_success() 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()))
.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(mNativeUwbManager).initSession(eq(TEST_SESSION_ID), anyByte(), eq(TEST_CHIP_ID));
verify(mUwbConfigurationManager)
.setAppConfigurations(eq(TEST_SESSION_ID), any(), eq(TEST_CHIP_ID));
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()))
.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()))
.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()))
.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()))
.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()))
.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 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 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<Params> paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class);
verify(mUwbConfigurationManager).setAppConfigurations(
eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID));
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<AlarmManager.OnAlarmListener> 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));
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<Params> paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class);
verify(mUwbConfigurationManager).setAppConfigurations(
eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID));
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<Params> paramsArgumentCaptor = ArgumentCaptor.forClass(Params.class);
verify(mUwbConfigurationManager).setAppConfigurations(
eq(TEST_SESSION_ID), paramsArgumentCaptor.capture(), eq(TEST_CHIP_ID));
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));
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 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);
verify(uwbSession.getIUwbRangingCallbacks()).onRangingOpenFailed(
eq(uwbSession.getSessionHandle()), eq(StateChangeReason.SYSTEM_POLICY), any());
// No OPEN_RANGING message scheduled.
assertThat(mTestLooper.isIdle()).isFalse();
}
private UwbSession prepareExistingUwbSession() throws Exception {
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);
mTestLooper.nextMessage(); // remove the OPEN_RANGING msg;
assertThat(mTestLooper.isIdle()).isFalse();
return uwbSession;
}
private UwbSession prepareExistingUwbSessionActive() throws Exception {
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();
return uwbSession;
}
private UwbSession prepareExistingCccUwbSession() throws Exception {
UwbSession uwbSession = setUpCccUwbSessionForExecution();
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;
}
@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() 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));
}
@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 {
startRanging_onRangeDataNotificationContinuousErrors(RANGING_MEASUREMENT_TYPE_TWO_WAY);
}
@Test
public void execStartRanging_owrAoa_onRangeDataNotificationContinuousErrors() throws Exception {
startRanging_onRangeDataNotificationContinuousErrors(RANGING_MEASUREMENT_TYPE_OWR_AOA);
}
private void startRanging_onRangeDataNotificationContinuousErrors(
int rangingMeasurementType) 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 with an error.
UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData(
rangingMeasurementType, MAC_ADDRESSING_MODE_EXTENDED,
UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT);
mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData);
verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData);
ArgumentCaptor<AlarmManager.OnAlarmListener> 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(
rangingMeasurementType, MAC_ADDRESSING_MODE_EXTENDED,
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));
verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession));
}
@Test
public void
execStartRanging_onRangeDataNotificationContinuousErrors_WhenErrorStreakTimerDisabled()
throws Exception {
when(mDeviceConfigFacade.isRangingErrorStreakTimerEnabled()).thenReturn(false);
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 with an error.
UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData(
RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED,
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();
// 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 with an error.
UwbRangingData uwbRangingData = UwbTestUtils.generateRangingData(
RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED,
UwbUciConstants.STATUS_CODE_RANGING_RX_TIMEOUT);
mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData);
verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData);
ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
verify(mAlarmManager).setExact(
anyInt(), anyLong(), anyString(), alarmListenerCaptor.capture(), any());
assertThat(alarmListenerCaptor.getValue()).isNotNull();
// Send success and ensure that the timer is cancelled.
uwbRangingData = UwbTestUtils.generateRangingData(
RANGING_MEASUREMENT_TYPE_TWO_WAY, MAC_ADDRESSING_MODE_EXTENDED,
UwbUciConstants.STATUS_CODE_OK);
mUwbSessionManager.onRangeDataNotificationReceived(uwbRangingData);
verify(mUwbSessionNotificationManager).onRangingResult(uwbSession, uwbRangingData);
verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
}
@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 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 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();
verify(mUwbSessionNotificationManager).onRangingStartFailed(
eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED));
verify(mUwbMetrics).longRangingStartEvent(
eq(uwbSession), eq(UwbUciConstants.STATUS_CODE_FAILED));
}
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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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);
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_success_sequenceNumberRollover() throws Exception {
// Setup a UwbSession to start ranging (and move it to active state).
UwbSession uwbSession = prepareExistingUwbSessionActive();
clearInvocations(mNativeUwbManager);
// Send 257 data packets on the UWB session, so that the UCI sequence number rolls over,
// back to 0.
when(mNativeUwbManager.sendData(anyInt(), any(), anyByte(), anyByte(), any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
for (int i = 0; i <= 256; i++) {
mUwbSessionManager.sendData(uwbSession.getSessionHandle(), PEER_EXTENDED_UWB_ADDRESS,
PERSISTABLE_BUNDLE, DATA_PAYLOAD);
mTestLooper.dispatchNext();
}
// Verify that there are 257 calls to mNativeUwbManager.sendData(), with the important
// thing here being that there should be 2 calls for sequence_number = 0, and 1 call for all
// the other sequence number values [1-255].
for (int i = 0; i < 256; i++) {
int expectedCount = (i == 0) ? 2 : 1;
verify(mNativeUwbManager, times(expectedCount)).sendData(eq(TEST_SESSION_ID),
eq(PEER_EXTENDED_UWB_ADDRESS.toBytes()),
eq(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), eq((byte) i),
eq(DATA_PAYLOAD), eq(TEST_CHIP_ID));
}
verifyNoMoreInteractions(mNativeUwbManager);
verify(mUwbMetrics, times(257)).logDataTx(eq(uwbSession),
eq(UwbUciConstants.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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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);
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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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);
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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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);
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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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(UwbUciConstants.UWB_DESTINATION_END_POINT_HOST), 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
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));
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, UwbUciConstants.UWB_SESSION_STATE_IDLE)
.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 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 {
UwbSession uwbSession = prepareExistingUwbSession();
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();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
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()))
.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 =
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 execReconfigureRemoveControleeV1_success() throws Exception {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParams(FiraParams.MULTICAST_LIST_UPDATE_ACTION_DELETE);
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
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()))
.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 = reconfigureParams.getAddressList()[0].toBytes();
verify(mNativeUwbManager).controllerMulticastListUpdate(
uwbSession.getSessionId(), reconfigureParams.getAction(), 1,
dstAddress, reconfigureParams.getSubSessionIdList(), null,
uwbSession.getChipId());
verify(mUwbSessionNotificationManager).onControleeRemoved(eq(uwbSession));
verify(mUwbSessionNotificationManager).onRangingReconfigured(eq(uwbSession));
}
@Test
public void execReconfigureAddControleeV2_success() throws Exception {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParamsV2();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
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()))
.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 = 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 execReconfigure_nativeUpdateFailed() throws Exception {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParamsV2();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED);
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 {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParamsV2();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
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 });
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 {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParamsV2();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_OK);
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()))
.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));
verify(mUwbMetrics).longRangingStopEvent(eq(uwbSession));
}
@Test
public void execReconfigure_setAppConfigurationsFailed() throws Exception {
UwbSession uwbSession = prepareExistingUwbSession();
FiraRangingReconfigureParams reconfigureParams =
buildReconfigureParamsV2();
when(mNativeUwbManager
.controllerMulticastListUpdate(anyInt(), anyInt(), anyInt(), any(), any(),
any(), anyString()))
.thenReturn((byte) UwbUciConstants.STATUS_CODE_FAILED);
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()))
.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 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 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());
mUwbSessionManager.deInitSession(mock(SessionHandle.class));
verify(mUwbSessionManager).getUwbSession(eq(TEST_SESSION_ID));
assertThat(mTestLooper.nextMessage().what).isEqualTo(5); // SESSION_DEINIT
verifyZeroInteractions(mUwbAdvertiseManager);
}
@Test
public void deInitSession_success_afterOwrAoaMeasurement() {
UwbSession mockUwbSession = mock(UwbSession.class);
when(mockUwbSession.getWaitObj()).thenReturn(mock(WaitObj.class));
when(mockUwbSession.getSessionHandle()).thenReturn(mock(SessionHandle.class));
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());
mUwbSessionManager.deInitSession(mock(SessionHandle.class));
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.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.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.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(), 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.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.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 {
UwbSession uwbSession = prepareExistingUwbSession();
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, SOURCE_END_POINT, DEST_END_POINT,
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.
Params firaParams = setupFiraParams(
RANGING_DEVICE_ROLE_OBSERVER, Optional.of(ROUND_USAGE_OWR_AOA_MEASUREMENT));
when(uwbSession.getParams()).thenReturn(firaParams);
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(), 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.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.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());
}
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.sourceEndPoint = SOURCE_END_POINT;
info.destEndPoint = DEST_END_POINT;
info.payload = DATA_PAYLOAD;
return info;
}
}