Loading core/java/android/uwb/UwbManager.java +1 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.AttributionSource; import android.content.Context; import android.content.ContextParams; import android.os.CancellationSignal; import android.os.IBinder; import android.os.PersistableBundle; Loading @@ -49,7 +47,7 @@ import java.util.concurrent.Executor; @SystemApi @SystemService(Context.UWB_SERVICE) public final class UwbManager { private static final String SERVICE_NAME = "uwb"; private static final String SERVICE_NAME = Context.UWB_SERVICE; private final Context mContext; private final IUwbAdapter mUwbAdapter; Loading services/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ filegroup { ":services.texttospeech-sources", ":services.usage-sources", ":services.usb-sources", ":services.uwb-sources", ":services.voiceinteraction-sources", ":services.wifi-sources", ], Loading Loading @@ -129,6 +130,7 @@ java_library { "services.texttospeech", "services.usage", "services.usb", "services.uwb", "services.voiceinteraction", "services.wifi", "service-blobstore", Loading services/java/com/android/server/SystemServer.java +7 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,7 @@ public final class SystemServer implements Dumpable { private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService"; private static final String GAME_MANAGER_SERVICE_CLASS = "com.android.server.app.GameManagerService$Lifecycle"; private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; Loading Loading @@ -2637,6 +2638,12 @@ public final class SystemServer implements Dumpable { LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal()); t.traceEnd(); if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) { t.traceBegin("UwbService"); mSystemServiceManager.startService(UWB_SERVICE_CLASS); t.traceEnd(); } t.traceBegin("StartBootPhaseDeviceSpecificServicesReady"); mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY); t.traceEnd(); Loading services/tests/servicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ android_test { "services.net", "services.people", "services.usage", "services.uwb", "guava", "androidx.test.core", "androidx.test.ext.truth", Loading services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.uwb; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.IBinder; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; import android.test.suitebuilder.annotation.SmallTest; import android.uwb.IUwbAdapter; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbRangingCallbacks; import android.uwb.RangingReport; import android.uwb.RangingSession; import android.uwb.SessionHandle; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Tests for {@link UwbServiceImpl}. */ @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class UwbServiceImplTest { @Mock private IUwbAdapter mVendorService; @Mock private IBinder mVendorServiceBinder; @Mock private Context mContext; @Mock private UwbInjector mUwbInjector; @Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor; @Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor; @Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor; private UwbServiceImpl mUwbServiceImpl; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mUwbInjector.getVendorService()).thenReturn(mVendorService); when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder); mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector); } @Test public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception { when(mUwbInjector.getVendorService()).thenReturn(null); final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); try { mUwbServiceImpl.registerAdapterStateCallbacks(cb); fail(); } catch (IllegalStateException e) { /* pass */ } } @Test public void testRegisterAdapterStateCallbacks() throws Exception { final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); mUwbServiceImpl.registerAdapterStateCallbacks(cb); verify(mVendorService).registerAdapterStateCallbacks(cb); } @Test public void testUnregisterAdapterStateCallbacks() throws Exception { final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); mUwbServiceImpl.unregisterAdapterStateCallbacks(cb); verify(mVendorService).unregisterAdapterStateCallbacks(cb); } @Test public void testGetTimestampResolutionNanos() throws Exception { final long timestamp = 34L; when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp); assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp); verify(mVendorService).getTimestampResolutionNanos(); } @Test public void testGetSpecificationInfo() throws Exception { final PersistableBundle specification = new PersistableBundle(); when(mVendorService.getSpecificationInfo()).thenReturn(specification); assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification); verify(mVendorService).getSpecificationInfo(); } @Test public void testOpenRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); } @Test public void testStartRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final PersistableBundle parameters = new PersistableBundle(); mUwbServiceImpl.startRanging(sessionHandle, parameters); verify(mVendorService).startRanging(sessionHandle, parameters); } @Test public void testReconfigureRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final PersistableBundle parameters = new PersistableBundle(); mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters); verify(mVendorService).reconfigureRanging(sessionHandle, parameters); } @Test public void testStopRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); mUwbServiceImpl.stopRanging(sessionHandle); verify(mVendorService).stopRanging(sessionHandle); } @Test public void testCloseRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); mUwbServiceImpl.closeRanging(sessionHandle); verify(mVendorService).closeRanging(sessionHandle); } @Test public void testRangingCallbacks() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); // Invoke vendor service callbacks and ensure that the corresponding app callback is // invoked. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); mRangingCbCaptor.getValue().onRangingOpenFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingOpenFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); verify(cb).onRangingStarted(sessionHandle, parameters); mRangingCbCaptor.getValue().onRangingStartFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStartFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters); verify(cb).onRangingReconfigured(sessionHandle, parameters); mRangingCbCaptor.getValue().onRangingReconfigureFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingReconfigureFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStopped( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStopped( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStopFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStopFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); final RangingReport rangingReport = new RangingReport.Builder().build(); mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport); verify(cb).onRangingResult(sessionHandle, rangingReport); mRangingCbCaptor.getValue().onRangingClosed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingClosed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); } @Test public void testHandleClientDeath() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt()); assertThat(mClientDeathCaptor.getValue()).isNotNull(); clearInvocations(cb); // Invoke cb, ensure it reaches the client. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); // Trigger client death and ensure the session is stopped. mClientDeathCaptor.getValue().binderDied(); verify(mVendorService).stopRanging(sessionHandle); verify(mVendorService).closeRanging(sessionHandle); // Invoke cb, it should be ignored. mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); verify(cb, never()).onRangingStarted(any(), any()); } @Test public void testHandleVendorServiceDeath() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt()); assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull(); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); clearInvocations(cb); // Invoke cb, ensure it reaches the client. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); // Trigger vendor service death and ensure that the client is informed of session end. mVendorServiceDeathCaptor.getValue().binderDied(); verify(cb).onRangingClosed( eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN), argThat((p) -> p.isEmpty())); } } Loading
core/java/android/uwb/UwbManager.java +1 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.AttributionSource; import android.content.Context; import android.content.ContextParams; import android.os.CancellationSignal; import android.os.IBinder; import android.os.PersistableBundle; Loading @@ -49,7 +47,7 @@ import java.util.concurrent.Executor; @SystemApi @SystemService(Context.UWB_SERVICE) public final class UwbManager { private static final String SERVICE_NAME = "uwb"; private static final String SERVICE_NAME = Context.UWB_SERVICE; private final Context mContext; private final IUwbAdapter mUwbAdapter; Loading
services/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ filegroup { ":services.texttospeech-sources", ":services.usage-sources", ":services.usb-sources", ":services.uwb-sources", ":services.voiceinteraction-sources", ":services.wifi-sources", ], Loading Loading @@ -129,6 +130,7 @@ java_library { "services.texttospeech", "services.usage", "services.usb", "services.uwb", "services.voiceinteraction", "services.wifi", "service-blobstore", Loading
services/java/com/android/server/SystemServer.java +7 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,7 @@ public final class SystemServer implements Dumpable { private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService"; private static final String GAME_MANAGER_SERVICE_CLASS = "com.android.server.app.GameManagerService$Lifecycle"; private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; Loading Loading @@ -2637,6 +2638,12 @@ public final class SystemServer implements Dumpable { LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal()); t.traceEnd(); if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) { t.traceBegin("UwbService"); mSystemServiceManager.startService(UWB_SERVICE_CLASS); t.traceEnd(); } t.traceBegin("StartBootPhaseDeviceSpecificServicesReady"); mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY); t.traceEnd(); Loading
services/tests/servicestests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ android_test { "services.net", "services.people", "services.usage", "services.uwb", "guava", "androidx.test.core", "androidx.test.ext.truth", Loading
services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java 0 → 100644 +299 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.uwb; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.os.IBinder; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; import android.test.suitebuilder.annotation.SmallTest; import android.uwb.IUwbAdapter; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbRangingCallbacks; import android.uwb.RangingReport; import android.uwb.RangingSession; import android.uwb.SessionHandle; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Tests for {@link UwbServiceImpl}. */ @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class UwbServiceImplTest { @Mock private IUwbAdapter mVendorService; @Mock private IBinder mVendorServiceBinder; @Mock private Context mContext; @Mock private UwbInjector mUwbInjector; @Captor private ArgumentCaptor<IUwbRangingCallbacks> mRangingCbCaptor; @Captor private ArgumentCaptor<IBinder.DeathRecipient> mClientDeathCaptor; @Captor private ArgumentCaptor<IBinder.DeathRecipient> mVendorServiceDeathCaptor; private UwbServiceImpl mUwbServiceImpl; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mUwbInjector.getVendorService()).thenReturn(mVendorService); when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder); mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector); } @Test public void testApiCallThrowsIllegalStateExceptionIfVendorServiceNotFound() throws Exception { when(mUwbInjector.getVendorService()).thenReturn(null); final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); try { mUwbServiceImpl.registerAdapterStateCallbacks(cb); fail(); } catch (IllegalStateException e) { /* pass */ } } @Test public void testRegisterAdapterStateCallbacks() throws Exception { final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); mUwbServiceImpl.registerAdapterStateCallbacks(cb); verify(mVendorService).registerAdapterStateCallbacks(cb); } @Test public void testUnregisterAdapterStateCallbacks() throws Exception { final IUwbAdapterStateCallbacks cb = mock(IUwbAdapterStateCallbacks.class); mUwbServiceImpl.unregisterAdapterStateCallbacks(cb); verify(mVendorService).unregisterAdapterStateCallbacks(cb); } @Test public void testGetTimestampResolutionNanos() throws Exception { final long timestamp = 34L; when(mVendorService.getTimestampResolutionNanos()).thenReturn(timestamp); assertThat(mUwbServiceImpl.getTimestampResolutionNanos()).isEqualTo(timestamp); verify(mVendorService).getTimestampResolutionNanos(); } @Test public void testGetSpecificationInfo() throws Exception { final PersistableBundle specification = new PersistableBundle(); when(mVendorService.getSpecificationInfo()).thenReturn(specification); assertThat(mUwbServiceImpl.getSpecificationInfo()).isEqualTo(specification); verify(mVendorService).getSpecificationInfo(); } @Test public void testOpenRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); } @Test public void testStartRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final PersistableBundle parameters = new PersistableBundle(); mUwbServiceImpl.startRanging(sessionHandle, parameters); verify(mVendorService).startRanging(sessionHandle, parameters); } @Test public void testReconfigureRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final PersistableBundle parameters = new PersistableBundle(); mUwbServiceImpl.reconfigureRanging(sessionHandle, parameters); verify(mVendorService).reconfigureRanging(sessionHandle, parameters); } @Test public void testStopRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); mUwbServiceImpl.stopRanging(sessionHandle); verify(mVendorService).stopRanging(sessionHandle); } @Test public void testCloseRanging() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); mUwbServiceImpl.closeRanging(sessionHandle); verify(mVendorService).closeRanging(sessionHandle); } @Test public void testRangingCallbacks() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); // Invoke vendor service callbacks and ensure that the corresponding app callback is // invoked. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); mRangingCbCaptor.getValue().onRangingOpenFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingOpenFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); verify(cb).onRangingStarted(sessionHandle, parameters); mRangingCbCaptor.getValue().onRangingStartFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStartFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingReconfigured(sessionHandle, parameters); verify(cb).onRangingReconfigured(sessionHandle, parameters); mRangingCbCaptor.getValue().onRangingReconfigureFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingReconfigureFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStopped( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStopped( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); mRangingCbCaptor.getValue().onRangingStopFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingStopFailed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); final RangingReport rangingReport = new RangingReport.Builder().build(); mRangingCbCaptor.getValue().onRangingResult(sessionHandle, rangingReport); verify(cb).onRangingResult(sessionHandle, rangingReport); mRangingCbCaptor.getValue().onRangingClosed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); verify(cb).onRangingClosed( sessionHandle, RangingSession.Callback.REASON_GENERIC_ERROR, parameters); } @Test public void testHandleClientDeath() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); verify(cbBinder).linkToDeath(mClientDeathCaptor.capture(), anyInt()); assertThat(mClientDeathCaptor.getValue()).isNotNull(); clearInvocations(cb); // Invoke cb, ensure it reaches the client. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); // Trigger client death and ensure the session is stopped. mClientDeathCaptor.getValue().binderDied(); verify(mVendorService).stopRanging(sessionHandle); verify(mVendorService).closeRanging(sessionHandle); // Invoke cb, it should be ignored. mRangingCbCaptor.getValue().onRangingStarted(sessionHandle, parameters); verify(cb, never()).onRangingStarted(any(), any()); } @Test public void testHandleVendorServiceDeath() throws Exception { final SessionHandle sessionHandle = new SessionHandle(5); final IUwbRangingCallbacks cb = mock(IUwbRangingCallbacks.class); final PersistableBundle parameters = new PersistableBundle(); final IBinder cbBinder = mock(IBinder.class); when(cb.asBinder()).thenReturn(cbBinder); mUwbServiceImpl.openRanging(sessionHandle, cb, parameters); verify(mVendorServiceBinder).linkToDeath(mVendorServiceDeathCaptor.capture(), anyInt()); assertThat(mVendorServiceDeathCaptor.getValue()).isNotNull(); verify(mVendorService).openRanging( eq(sessionHandle), mRangingCbCaptor.capture(), eq(parameters)); assertThat(mRangingCbCaptor.getValue()).isNotNull(); clearInvocations(cb); // Invoke cb, ensure it reaches the client. mRangingCbCaptor.getValue().onRangingOpened(sessionHandle); verify(cb).onRangingOpened(sessionHandle); // Trigger vendor service death and ensure that the client is informed of session end. mVendorServiceDeathCaptor.getValue().binderDied(); verify(cb).onRangingClosed( eq(sessionHandle), eq(RangingSession.Callback.REASON_UNKNOWN), argThat((p) -> p.isEmpty())); } }