1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.uwb;
18 
19 import static android.uwb.UwbManager.MESSAGE_TYPE_COMMAND;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.junit.Assert.assertThrows;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.never;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.content.AttributionSource;
34 import android.content.Context;
35 import android.os.PersistableBundle;
36 import android.os.RemoteException;
37 import android.uwb.UwbManager.AdapterStateCallback;
38 import android.uwb.UwbManager.AdfProvisionStateCallback;
39 import android.uwb.UwbManager.UwbVendorUciCallback;
40 
41 import androidx.test.ext.junit.runners.AndroidJUnit4;
42 import androidx.test.filters.SmallTest;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.Mock;
48 import org.mockito.MockitoAnnotations;
49 
50 import java.util.List;
51 import java.util.concurrent.Executor;
52 import java.util.function.Consumer;
53 
54 /**
55  * Test of {@link UwbManager}.
56  */
57 @SmallTest
58 @RunWith(AndroidJUnit4.class)
59 public class UwbManagerTest {
60 
61     @Mock private Context mContext;
62     @Mock private IUwbAdapter mIUwbAdapter;
63     @Mock private AdapterStateCallback mAdapterStateCallback;
64     @Mock private AdapterStateCallback mAdapterStateCallback2;
65     @Mock private UwbVendorUciCallback mUwbVendorUciCallback;
66     @Mock private UwbVendorUciCallback mUwbVendorUciCallback2;
67 
68     private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
69     private static final String CHIP_ID = "CHIP_ID";
70     private static final PersistableBundle PARAMS = new PersistableBundle();
71     private static final PersistableBundle PARAMS2 = new PersistableBundle();
72     private static final byte[] PAYLOAD = new byte[] {0x0, 0x1};
73     private static final int MT = 1;
74     private static final int GID = 9;
75     private static final int OID = 1;
76     private static final int UID = 343453;
77     private static final String PACKAGE_NAME = "com.uwb.test";
78     private static final AttributionSource ATTRIBUTION_SOURCE =
79             new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build();
80     private static final long TIME_NANOS = 1001;
81     private static final long TIME_NANOS2 = 1002;
82 
83     private UwbManager mUwbManager;
84 
85     @Before
setUp()86     public void setUp() throws Exception {
87         MockitoAnnotations.initMocks(this);
88         when(mContext.getAttributionSource()).thenReturn(ATTRIBUTION_SOURCE);
89 
90         mUwbManager = new UwbManager(mContext, mIUwbAdapter);
91     }
92 
93     @Test
testRegisterUnregisterCallbacks()94     public void testRegisterUnregisterCallbacks() throws Exception {
95         // Register/unregister AdapterStateCallbacks
96         mUwbManager.registerAdapterStateCallback(EXECUTOR, mAdapterStateCallback);
97         verify(mIUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
98         mUwbManager.registerAdapterStateCallback(EXECUTOR, mAdapterStateCallback2);
99         verify(mIUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
100         mUwbManager.unregisterAdapterStateCallback(mAdapterStateCallback);
101         verify(mIUwbAdapter, never()).unregisterAdapterStateCallbacks(any());
102         mUwbManager.unregisterAdapterStateCallback(mAdapterStateCallback2);
103         verify(mIUwbAdapter, times(1)).unregisterAdapterStateCallbacks(any());
104 
105         // Register/unregister UwbVendorUciCallback
106         mUwbManager.registerUwbVendorUciCallback(EXECUTOR, mUwbVendorUciCallback);
107         verify(mIUwbAdapter, times(1)).registerVendorExtensionCallback(any());
108         mUwbManager.registerUwbVendorUciCallback(EXECUTOR, mUwbVendorUciCallback2);
109         verify(mIUwbAdapter, times(1)).registerVendorExtensionCallback(any());
110         mUwbManager.unregisterUwbVendorUciCallback(mUwbVendorUciCallback);
111         verify(mIUwbAdapter, never()).unregisterVendorExtensionCallback(any());
112         mUwbManager.unregisterUwbVendorUciCallback(mUwbVendorUciCallback2);
113         verify(mIUwbAdapter, times(1)).unregisterVendorExtensionCallback(any());
114     }
115 
116     @Test
testGettersAndSetters()117     public void testGettersAndSetters() throws Exception {
118         // Get SpecificationInfo
119         when(mIUwbAdapter.getSpecificationInfo(/*chipId=*/ null)).thenReturn(PARAMS);
120         assertThat(mUwbManager.getSpecificationInfo()).isEqualTo(PARAMS);
121         when(mIUwbAdapter.getSpecificationInfo(CHIP_ID)).thenReturn(PARAMS2);
122         assertThat(mUwbManager.getSpecificationInfo(CHIP_ID)).isEqualTo(PARAMS2);
123         doThrow(new RemoteException()).when(mIUwbAdapter).getSpecificationInfo(/*chipId=*/ null);
124         assertThrows(RuntimeException.class, () -> mUwbManager.getSpecificationInfo());
125 
126         // Get elapsedRealtimeResolutionNanos
127         when(mIUwbAdapter.getTimestampResolutionNanos(/*chipId=*/ null)).thenReturn(TIME_NANOS);
128         assertThat(mUwbManager.elapsedRealtimeResolutionNanos()).isEqualTo(TIME_NANOS);
129         when(mIUwbAdapter.getTimestampResolutionNanos(CHIP_ID)).thenReturn(TIME_NANOS2);
130         assertThat(mUwbManager.elapsedRealtimeResolutionNanos(CHIP_ID)).isEqualTo(TIME_NANOS2);
131         doThrow(new RemoteException())
132                 .when(mIUwbAdapter)
133                 .getTimestampResolutionNanos(/*chipId=*/ null);
134         assertThrows(RuntimeException.class, () -> mUwbManager.elapsedRealtimeResolutionNanos());
135 
136         // setUwbEnabled
137         mUwbManager.setUwbEnabled(/*enabled=*/ true);
138         verify(mIUwbAdapter, times(1)).setEnabled(true);
139 
140         // Get IsUwbEnabled
141         when(mIUwbAdapter.getAdapterState()).thenReturn(AdapterState.STATE_ENABLED_ACTIVE);
142         assertThat(mUwbManager.isUwbEnabled()).isTrue();
143         when(mIUwbAdapter.getAdapterState()).thenReturn(AdapterState.STATE_ENABLED_INACTIVE);
144         assertThat(mUwbManager.isUwbEnabled()).isTrue();
145         when(mIUwbAdapter.getAdapterState()).thenReturn(AdapterState.STATE_DISABLED);
146         assertThat(mUwbManager.isUwbEnabled()).isFalse();
147         doThrow(new RemoteException()).when(mIUwbAdapter).getAdapterState();
148         assertThrows(RuntimeException.class, () -> mUwbManager.isUwbEnabled());
149 
150         // getChipInfos
151         when(mIUwbAdapter.getChipInfos()).thenReturn(List.of(PARAMS));
152         assertThat(mUwbManager.getChipInfos()).isEqualTo(List.of(PARAMS));
153         doThrow(new RemoteException()).when(mIUwbAdapter).getChipInfos();
154         assertThrows(RuntimeException.class, () -> mUwbManager.getChipInfos());
155 
156         // getDefaultChipId
157         when(mIUwbAdapter.getDefaultChipId()).thenReturn(CHIP_ID);
158         assertThat(mUwbManager.getDefaultChipId()).isEqualTo(CHIP_ID);
159         doThrow(new RemoteException()).when(mIUwbAdapter).getDefaultChipId();
160         assertThrows(RuntimeException.class, () -> mUwbManager.getDefaultChipId());
161 
162         // getAllServiceProfiles
163         when(mIUwbAdapter.getAllServiceProfiles()).thenReturn(PARAMS);
164         assertThat(mUwbManager.getAllServiceProfiles()).isEqualTo(PARAMS);
165         doThrow(new RemoteException()).when(mIUwbAdapter).getAllServiceProfiles();
166         assertThrows(RuntimeException.class, () -> mUwbManager.getAllServiceProfiles());
167 
168         // getAllServiceProfiles
169         when(mIUwbAdapter.getAdfProvisioningAuthorities(PARAMS)).thenReturn(PARAMS);
170         assertThat(mUwbManager.getAdfProvisioningAuthorities(PARAMS)).isEqualTo(PARAMS);
171         doThrow(new RemoteException()).when(mIUwbAdapter).getAdfProvisioningAuthorities(PARAMS);
172         assertThrows(
173                 RuntimeException.class, () -> mUwbManager.getAdfProvisioningAuthorities(PARAMS));
174 
175         // getAdfCertificateInfo
176         when(mIUwbAdapter.getAdfCertificateAndInfo(PARAMS)).thenReturn(PARAMS);
177         assertThat(mUwbManager.getAdfCertificateInfo(PARAMS)).isEqualTo(PARAMS);
178         doThrow(new RemoteException()).when(mIUwbAdapter).getAdfCertificateAndInfo(PARAMS);
179         assertThrows(RuntimeException.class, () -> mUwbManager.getAdfCertificateInfo(PARAMS));
180     }
181 
182     @Test
testOpenRangingSession()183     public void testOpenRangingSession() throws Exception {
184         RangingSession.Callback callback = mock(RangingSession.Callback.class);
185         // null chip id
186         mUwbManager.openRangingSession(PARAMS, EXECUTOR, callback);
187         verify(mIUwbAdapter, times(1))
188                 .openRanging(eq(ATTRIBUTION_SOURCE), any(), any(), eq(PARAMS), eq(null));
189 
190         // Chip id not on valid list
191         assertThrows(
192                 IllegalArgumentException.class,
193                 () -> mUwbManager.openRangingSession(PARAMS, EXECUTOR, callback, CHIP_ID));
194 
195         // Chip id on valid list
196         when(mIUwbAdapter.getChipIds()).thenReturn(List.of(CHIP_ID));
197         mUwbManager.openRangingSession(PARAMS, EXECUTOR, callback, CHIP_ID);
198         verify(mIUwbAdapter, times(1))
199                 .openRanging(eq(ATTRIBUTION_SOURCE), any(), any(), eq(PARAMS), eq(CHIP_ID));
200     }
201 
202     @Test
testAddServiceProfile()203     public void testAddServiceProfile() throws Exception {
204         when(mIUwbAdapter.addServiceProfile(PARAMS)).thenReturn(PARAMS);
205         assertThat(mUwbManager.addServiceProfile(PARAMS)).isEqualTo(PARAMS);
206         doThrow(new RemoteException()).when(mIUwbAdapter).addServiceProfile(PARAMS);
207         assertThrows(RuntimeException.class, () -> mUwbManager.addServiceProfile(PARAMS));
208     }
209 
210     @Test
testRemoveServiceProfile()211     public void testRemoveServiceProfile() throws Exception {
212         when(mIUwbAdapter.removeServiceProfile(PARAMS))
213                 .thenReturn(UwbManager.REMOVE_SERVICE_PROFILE_SUCCESS);
214         assertThat(mUwbManager.removeServiceProfile(PARAMS))
215                 .isEqualTo(UwbManager.REMOVE_SERVICE_PROFILE_SUCCESS);
216         doThrow(new RemoteException()).when(mIUwbAdapter).removeServiceProfile(PARAMS);
217         assertThrows(RuntimeException.class, () -> mUwbManager.removeServiceProfile(PARAMS));
218     }
219 
220     @Test
testProvisionProfileAdfByScript()221     public void testProvisionProfileAdfByScript() throws Exception {
222         AdfProvisionStateCallback cb = mock(AdfProvisionStateCallback.class);
223         assertThrows(
224                 IllegalArgumentException.class,
225                 () -> mUwbManager.provisionProfileAdfByScript(PARAMS, /*executor=*/ null, cb));
226         assertThrows(
227                 IllegalArgumentException.class,
228                 () ->
229                         mUwbManager.provisionProfileAdfByScript(
230                                 PARAMS, EXECUTOR, /*callback=*/ null));
231         doThrow(new RemoteException())
232                 .when(mIUwbAdapter)
233                 .provisionProfileAdfByScript(eq(PARAMS), any());
234         assertThrows(
235                 RuntimeException.class,
236                 () -> mUwbManager.provisionProfileAdfByScript(PARAMS, EXECUTOR, cb));
237     }
238 
239     @Test
testRemoveProfileAdf()240     public void testRemoveProfileAdf() throws Exception {
241         when(mIUwbAdapter.removeProfileAdf(PARAMS))
242                 .thenReturn(UwbManager.REMOVE_PROFILE_ADF_SUCCESS);
243         assertThat(mUwbManager.removeProfileAdf(PARAMS))
244                 .isEqualTo(UwbManager.REMOVE_PROFILE_ADF_SUCCESS);
245         doThrow(new RemoteException()).when(mIUwbAdapter).removeProfileAdf(PARAMS);
246         assertThrows(RuntimeException.class, () -> mUwbManager.removeProfileAdf(PARAMS));
247     }
248 
249     @Test
testSendVendorUciMessage()250     public void testSendVendorUciMessage() throws Exception {
251         when(mIUwbAdapter.sendVendorUciMessage(MESSAGE_TYPE_COMMAND, GID, OID, PAYLOAD))
252                 .thenReturn(UwbManager.SEND_VENDOR_UCI_SUCCESS);
253         assertThat(mUwbManager.sendVendorUciMessage(GID, OID, PAYLOAD))
254                 .isEqualTo(UwbManager.SEND_VENDOR_UCI_SUCCESS);
255         doThrow(new RemoteException()).when(mIUwbAdapter).sendVendorUciMessage(MESSAGE_TYPE_COMMAND,
256                 GID, OID, PAYLOAD);
257         assertThrows(
258                 RuntimeException.class, () -> mUwbManager.sendVendorUciMessage(GID, OID, PAYLOAD));
259     }
260 
261     @Test
testSendVendorUciMessageWithMessageType()262     public void testSendVendorUciMessageWithMessageType() throws Exception {
263         when(mIUwbAdapter.sendVendorUciMessage(MT, GID, OID, PAYLOAD))
264                 .thenReturn(UwbManager.SEND_VENDOR_UCI_SUCCESS);
265         assertThat(mUwbManager.sendVendorUciMessage(MT, GID, OID, PAYLOAD))
266                 .isEqualTo(UwbManager.SEND_VENDOR_UCI_SUCCESS);
267         doThrow(new RemoteException()).when(mIUwbAdapter).sendVendorUciMessage(MT, GID, OID,
268                 PAYLOAD);
269         assertThrows(
270                 RuntimeException.class, () -> mUwbManager.sendVendorUciMessage(MT, GID, OID,
271                         PAYLOAD));
272     }
273 
274     @Test
testGetUwbActivityEnergyInfoAsync()275     public void testGetUwbActivityEnergyInfoAsync() throws Exception {
276         Consumer<UwbActivityEnergyInfo> listener = mock(Consumer.class);
277         // null Executor
278         assertThrows(NullPointerException.class,
279                 () -> mUwbManager.getUwbActivityEnergyInfoAsync(null, listener));
280         // null listener
281         assertThrows(NullPointerException.class,
282                 () -> mUwbManager.getUwbActivityEnergyInfoAsync(EXECUTOR, null));
283 
284         mUwbManager.getUwbActivityEnergyInfoAsync(EXECUTOR, listener);
285         verify(mIUwbAdapter).getUwbActivityEnergyInfoAsync(
286                 any(IOnUwbActivityEnergyInfoListener.Stub.class));
287     }
288 }
289