1 /* 2 * Copyright (C) 2019 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 com.android.server.soundtrigger_middleware; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.fail; 25 import static org.junit.Assume.assumeTrue; 26 import static org.mockito.ArgumentMatchers.any; 27 import static org.mockito.ArgumentMatchers.anyInt; 28 import static org.mockito.ArgumentMatchers.anyLong; 29 import static org.mockito.ArgumentMatchers.eq; 30 import static org.mockito.Mockito.atMost; 31 import static org.mockito.Mockito.clearInvocations; 32 import static org.mockito.Mockito.doAnswer; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.verifyNoMoreInteractions; 36 import static org.mockito.Mockito.when; 37 38 import android.media.soundtrigger.ModelParameterRange; 39 import android.media.soundtrigger.Properties; 40 import android.media.soundtrigger.RecognitionConfig; 41 import android.media.soundtrigger.RecognitionStatus; 42 import android.media.soundtrigger.Status; 43 import android.media.soundtrigger_middleware.PhraseRecognitionEventSys; 44 import android.media.soundtrigger_middleware.RecognitionEventSys; 45 import android.os.HwParcel; 46 import android.os.IBinder; 47 import android.os.IHwBinder; 48 import android.os.IHwInterface; 49 import android.os.RemoteException; 50 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.junit.runners.Parameterized; 56 import org.mockito.ArgumentCaptor; 57 58 import java.util.concurrent.atomic.AtomicReference; 59 60 @RunWith(Parameterized.class) 61 public class SoundHw2CompatTest { 62 @Parameterized.Parameter public String mVersion; 63 64 private final Runnable mRebootRunnable = mock(Runnable.class); 65 private ISoundTriggerHal mCanonical; 66 private android.hardware.soundtrigger.V2_0.ISoundTriggerHw mHalDriver; 67 68 // We run the test once for every version of the underlying driver. 69 @Parameterized.Parameters data()70 public static Object[] data() { 71 return new String[]{"V2_0", "V2_1", "V2_2", "V2_3"}; 72 } 73 74 @Before setUp()75 public void setUp() throws Exception { 76 mHalDriver = (android.hardware.soundtrigger.V2_0.ISoundTriggerHw) mock(Class.forName( 77 String.format("android.hardware.soundtrigger.%s.ISoundTriggerHw", mVersion))); 78 79 clearInvocations(mRebootRunnable); 80 81 // This binder is associated with the mock, so it can be cast to either version of the 82 // HAL interface. 83 final IHwBinder binder = new IHwBinder() { 84 @Override 85 public void transact(int code, HwParcel request, HwParcel reply, int flags) 86 throws RemoteException { 87 // This is a little hacky, but a very easy way to gracefully reject a request for 88 // an unsupported interface (after queryLocalInterface() returns null, the client 89 // will attempt a remote transaction to obtain the interface. RemoteException will 90 // cause it to give up). 91 throw new RemoteException(); 92 } 93 94 @Override 95 public IHwInterface queryLocalInterface(String descriptor) { 96 if (descriptor.equals("android.hardware.soundtrigger@2.0::ISoundTriggerHw") 97 || descriptor.equals("android.hardware.soundtrigger@2.1::ISoundTriggerHw") 98 && mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw 99 || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw") 100 && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw 101 || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw") 102 && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { 103 return mHalDriver; 104 } 105 return null; 106 } 107 108 @Override 109 public boolean linkToDeath(DeathRecipient recipient, long cookie) { 110 try { 111 return mHalDriver.linkToDeath(recipient, cookie); 112 } catch (RemoteException e) { 113 throw e.rethrowAsRuntimeException(); 114 } 115 } 116 117 @Override 118 public boolean unlinkToDeath(DeathRecipient recipient) { 119 try { 120 return mHalDriver.unlinkToDeath(recipient); 121 } catch (RemoteException e) { 122 throw e.rethrowAsRuntimeException(); 123 } 124 } 125 }; 126 when(mHalDriver.asBinder()).thenReturn(binder); 127 128 android.hardware.soundtrigger.V2_3.Properties halProperties = 129 TestUtil.createDefaultProperties_2_3(); 130 doAnswer(invocation -> { 131 ((android.hardware.soundtrigger.V2_0.ISoundTriggerHw.getPropertiesCallback) invocation.getArgument( 132 0)).onValues(0, halProperties.base); 133 return null; 134 }).when(mHalDriver).getProperties(any()); 135 136 if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { 137 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = 138 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 139 doAnswer(invocation -> { 140 ((android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getProperties_2_3Callback) invocation.getArgument( 141 0)).onValues(0, halProperties); 142 return null; 143 }).when(driver).getProperties_2_3(any()); 144 } 145 146 mCanonical = SoundTriggerHw2Compat.create(mHalDriver, mRebootRunnable, null); 147 148 // During initialization any method can be called, but after we're starting to enforce that 149 // no additional methods are called. 150 clearInvocations(mHalDriver); 151 } 152 153 @After tearDown()154 public void tearDown() { 155 mCanonical.detach(); 156 verifyNoMoreInteractions(mHalDriver); 157 verifyNoMoreInteractions(mRebootRunnable); 158 } 159 160 @Test testSetUpAndTearDown()161 public void testSetUpAndTearDown() { 162 } 163 164 @Test testReboot()165 public void testReboot() { 166 mCanonical.reboot(); 167 verify(mRebootRunnable).run(); 168 } 169 170 @Test testGetProperties()171 public void testGetProperties() throws Exception { 172 Properties properties = mCanonical.getProperties(); 173 174 if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { 175 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = 176 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 177 // It is OK for the SUT to cache the properties, so the underlying method doesn't 178 // need to be called every single time. 179 verify(driver, atMost(1)).getProperties_2_3(any()); 180 TestUtil.validateDefaultProperties(properties); 181 } else { 182 // It is OK for the SUT to cache the properties, so the underlying method doesn't 183 // need to be called every single time. 184 verify(mHalDriver, atMost(1)).getProperties(any()); 185 TestUtil.validateDefaultProperties(properties, 0, ""); 186 } 187 } 188 loadGenericModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback)189 private int loadGenericModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback) 190 throws Exception { 191 final int handle = 29; 192 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel> modelCaptor = 193 ArgumentCaptor.forClass( 194 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel.class); 195 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor = 196 ArgumentCaptor.forClass( 197 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); 198 199 doAnswer(invocation -> { 200 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadSoundModelCallback 201 resultCallback = invocation.getArgument(3); 202 203 // This is the return of this method. 204 resultCallback.onValues(0, handle); 205 return null; 206 }).when(mHalDriver).loadSoundModel(any(), any(), anyInt(), any()); 207 208 assertEquals(handle, 209 mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback)); 210 211 verify(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture(), anyInt(), 212 any()); 213 214 TestUtil.validateGenericSoundModel_2_0(modelCaptor.getValue()); 215 validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); 216 return handle; 217 } 218 loadGenericModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback)219 private int loadGenericModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback) 220 throws Exception { 221 final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = 222 (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; 223 224 final int handle = 29; 225 AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> model = 226 new AtomicReference<>(); 227 ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor = 228 ArgumentCaptor.forClass( 229 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); 230 231 doAnswer(invocation -> { 232 // We need to dup the model, as it gets invalidated after the call returns. 233 model.set(TestUtil.dupModel_2_1(invocation.getArgument(0))); 234 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback 235 resultCallback = invocation.getArgument(3); 236 237 // This is the return of this method. 238 resultCallback.onValues(0, handle); 239 return null; 240 }).when(driver_2_1).loadSoundModel_2_1(any(), any(), anyInt(), any()); 241 242 assertEquals(handle, 243 mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback)); 244 245 verify(driver_2_1).loadSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(), any()); 246 247 TestUtil.validateGenericSoundModel_2_1(model.get()); 248 validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); 249 return handle; 250 } 251 loadGenericModel(ISoundTriggerHal.ModelCallback canonicalCallback)252 private int loadGenericModel(ISoundTriggerHal.ModelCallback canonicalCallback) 253 throws Exception { 254 if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { 255 return loadGenericModel_2_1(canonicalCallback); 256 } else { 257 return loadGenericModel_2_0(canonicalCallback); 258 } 259 } 260 261 @Test testLoadGenericModel()262 public void testLoadGenericModel() throws Exception { 263 ISoundTriggerHal.ModelCallback canonicalCallback = mock( 264 ISoundTriggerHal.ModelCallback.class); 265 loadGenericModel(canonicalCallback); 266 } 267 268 @Test testMaxModels()269 public void testMaxModels() throws Exception { 270 // Register global callback. 271 ISoundTriggerHal.GlobalCallback globalCallback = mock( 272 ISoundTriggerHal.GlobalCallback.class); 273 mCanonical.registerCallback(globalCallback); 274 275 ISoundTriggerHal.ModelCallback canonicalCallback = mock( 276 ISoundTriggerHal.ModelCallback.class); 277 final int maxModels = TestUtil.createDefaultProperties_2_0().maxSoundModels; 278 int[] modelHandles = new int[maxModels]; 279 280 // Load as many models as we're allowed. 281 for (int i = 0; i < maxModels; ++i) { 282 modelHandles[i] = loadGenericModel(canonicalCallback); 283 verifyNoMoreInteractions(mHalDriver); 284 clearInvocations(mHalDriver); 285 } 286 287 // Now try to load an additional one and expect failure without invoking the underlying 288 // driver. 289 try { 290 mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), canonicalCallback); 291 fail("Expected an exception"); 292 } catch (RecoverableException e) { 293 assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); 294 } 295 296 // Unload a single model and expect a onResourcesAvailable(). 297 mCanonical.unloadSoundModel(modelHandles[0]); 298 verify(mHalDriver).unloadSoundModel(modelHandles[0]); 299 300 mCanonical.flushCallbacks(); 301 verify(globalCallback).onResourcesAvailable(); 302 } 303 loadPhraseModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback)304 private void loadPhraseModel_2_0(ISoundTriggerHal.ModelCallback canonicalCallback) 305 throws Exception { 306 final int handle = 29; 307 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel> 308 modelCaptor = ArgumentCaptor.forClass( 309 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel.class); 310 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor = 311 ArgumentCaptor.forClass( 312 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); 313 314 doAnswer(invocation -> { 315 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadPhraseSoundModelCallback 316 resultCallback = invocation.getArgument(3); 317 318 // This is the return of this method. 319 resultCallback.onValues(0, handle); 320 return null; 321 }).when(mHalDriver).loadPhraseSoundModel(any(), any(), anyInt(), any()); 322 323 assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), 324 canonicalCallback)); 325 326 verify(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture(), 327 anyInt(), any()); 328 329 TestUtil.validatePhraseSoundModel_2_0(modelCaptor.getValue()); 330 validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); 331 } 332 loadPhraseModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback)333 private void loadPhraseModel_2_1(ISoundTriggerHal.ModelCallback canonicalCallback) 334 throws Exception { 335 final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = 336 (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; 337 338 final int handle = 29; 339 AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> model = 340 new AtomicReference<>(); 341 ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor = 342 ArgumentCaptor.forClass( 343 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); 344 345 doAnswer(invocation -> { 346 // We need to dup the model, as it gets invalidated after the call returns. 347 model.set(TestUtil.dupPhraseModel_2_1(invocation.getArgument(0))); 348 349 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback 350 resultCallback = invocation.getArgument(3); 351 352 // This is the return of this method. 353 resultCallback.onValues(0, handle); 354 return null; 355 }).when(driver_2_1).loadPhraseSoundModel_2_1(any(), any(), anyInt(), any()); 356 357 assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(), 358 canonicalCallback)); 359 360 verify(driver_2_1).loadPhraseSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(), 361 any()); 362 363 TestUtil.validatePhraseSoundModel_2_1(model.get()); 364 validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); 365 } 366 loadPhraseModel(ISoundTriggerHal.ModelCallback canonicalCallback)367 public void loadPhraseModel(ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception { 368 if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { 369 loadPhraseModel_2_1(canonicalCallback); 370 } else { 371 loadPhraseModel_2_0(canonicalCallback); 372 } 373 } 374 375 @Test testLoadPhraseModel()376 public void testLoadPhraseModel() throws Exception { 377 ISoundTriggerHal.ModelCallback canonicalCallback = mock( 378 ISoundTriggerHal.ModelCallback.class); 379 loadPhraseModel(canonicalCallback); 380 } 381 382 @Test testUnloadModel()383 public void testUnloadModel() throws Exception { 384 mCanonical.unloadSoundModel(14); 385 verify(mHalDriver).unloadSoundModel(14); 386 } 387 startRecognition_2_0(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)388 private void startRecognition_2_0(int handle, ISoundTriggerHal.ModelCallback canonicalCallback) 389 throws Exception { 390 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig> 391 configCaptor = ArgumentCaptor.forClass( 392 android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig.class); 393 ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor = 394 ArgumentCaptor.forClass( 395 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); 396 397 when(mHalDriver.startRecognition(eq(handle), any(), any(), anyInt())).thenReturn(0); 398 399 RecognitionConfig config = TestUtil.createRecognitionConfig(); 400 mCanonical.startRecognition(handle, 203, 204, config); 401 verify(mHalDriver).startRecognition(eq(handle), configCaptor.capture(), 402 callbackCaptor.capture(), anyInt()); 403 404 TestUtil.validateRecognitionConfig_2_0(configCaptor.getValue(), 203, 204); 405 validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); 406 } 407 startRecognition_2_1(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)408 private void startRecognition_2_1(int handle, ISoundTriggerHal.ModelCallback canonicalCallback) 409 throws Exception { 410 final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = 411 (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; 412 413 ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig> 414 configCaptor = ArgumentCaptor.forClass( 415 android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig.class); 416 ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor = 417 ArgumentCaptor.forClass( 418 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); 419 420 when(driver_2_1.startRecognition_2_1(eq(handle), any(), any(), anyInt())).thenReturn(0); 421 422 RecognitionConfig config = TestUtil.createRecognitionConfig(); 423 mCanonical.startRecognition(handle, 505, 506, config); 424 verify(driver_2_1).startRecognition_2_1(eq(handle), configCaptor.capture(), 425 callbackCaptor.capture(), anyInt()); 426 427 TestUtil.validateRecognitionConfig_2_1(configCaptor.getValue(), 505, 506); 428 validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); 429 } 430 startRecognition_2_3(int handle)431 private void startRecognition_2_3(int handle) throws Exception { 432 final android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = 433 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 434 ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> configCaptor = 435 ArgumentCaptor.forClass(android.hardware.soundtrigger.V2_3.RecognitionConfig.class); 436 437 when(driver_2_3.startRecognition_2_3(eq(handle), any())).thenReturn(0); 438 439 RecognitionConfig config = TestUtil.createRecognitionConfig(); 440 mCanonical.startRecognition(handle, 808, 909, config); 441 verify(driver_2_3).startRecognition_2_3(eq(handle), configCaptor.capture()); 442 TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 808, 909); 443 } 444 startRecognition(int handle, ISoundTriggerHal.ModelCallback canonicalCallback)445 private void startRecognition(int handle, ISoundTriggerHal.ModelCallback canonicalCallback) 446 throws Exception { 447 if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { 448 startRecognition_2_3(handle); 449 } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { 450 startRecognition_2_1(handle, canonicalCallback); 451 } else { 452 startRecognition_2_0(handle, canonicalCallback); 453 } 454 } 455 456 @Test testStartRecognition()457 public void testStartRecognition() throws Exception { 458 // First load. 459 ISoundTriggerHal.ModelCallback canonicalCallback = mock( 460 ISoundTriggerHal.ModelCallback.class); 461 final int handle = loadGenericModel(canonicalCallback); 462 463 // Then start. 464 startRecognition(handle, canonicalCallback); 465 } 466 467 @Test testStopRecognition()468 public void testStopRecognition() throws Exception { 469 mCanonical.stopRecognition(17); 470 verify(mHalDriver).stopRecognition(17); 471 } 472 473 @Test testForceRecognition()474 public void testForceRecognition() throws Exception { 475 if (mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw) { 476 android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver_2_2 = 477 (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver; 478 mCanonical.forceRecognitionEvent(14); 479 verify(driver_2_2).getModelState(14); 480 } else { 481 try { 482 mCanonical.forceRecognitionEvent(14); 483 fail("Expected an exception"); 484 } catch (RecoverableException e) { 485 assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode); 486 } 487 } 488 } 489 490 @Test testGetParameter()491 public void testGetParameter() throws Exception { 492 assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); 493 494 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = 495 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 496 497 doAnswer(invocation -> { 498 android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getParameterCallback resultCallback = 499 invocation.getArgument(2); 500 501 // This is the return of this method. 502 resultCallback.onValues(0, 99); 503 return null; 504 }).when(driver_2_3).getParameter(eq(21), eq(47), any()); 505 506 assertEquals(99, mCanonical.getModelParameter(21, 47)); 507 verify(driver_2_3).getParameter(eq(21), eq(47), any()); 508 } 509 510 @Test testSetParameter()511 public void testSetParameter() throws Exception { 512 assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); 513 514 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = 515 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 516 517 mCanonical.setModelParameter(212, 247, 80); 518 verify(driver_2_3).setParameter(212, 247, 80); 519 } 520 521 @Test testQueryParameterSupported()522 public void testQueryParameterSupported() throws Exception { 523 assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); 524 525 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = 526 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 527 528 doAnswer(invocation -> { 529 android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback 530 resultCallback = invocation.getArgument(2); 531 532 // This is the return of this method. 533 android.hardware.soundtrigger.V2_3.ModelParameterRange range = 534 new android.hardware.soundtrigger.V2_3.ModelParameterRange(); 535 range.start = 34; 536 range.end = 45; 537 android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange = 538 new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange(); 539 optionalRange.range(range); 540 resultCallback.onValues(0, optionalRange); 541 return null; 542 }).when(driver_2_3).queryParameter(eq(11), eq(12), any()); 543 544 ModelParameterRange range = mCanonical.queryParameter(11, 12); 545 assertNotNull(range); 546 assertEquals(34, range.minInclusive); 547 assertEquals(45, range.maxInclusive); 548 verify(driver_2_3).queryParameter(eq(11), eq(12), any()); 549 } 550 551 @Test testQueryParameterNotSupported()552 public void testQueryParameterNotSupported() throws Exception { 553 if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { 554 android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = 555 (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; 556 557 doAnswer(invocation -> { 558 android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback 559 resultCallback = invocation.getArgument(2); 560 561 // This is the return of this method. 562 android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange = 563 new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange(); 564 resultCallback.onValues(0, optionalRange); 565 return null; 566 }).when(driver_2_3).queryParameter(eq(11), eq(12), any()); 567 568 ModelParameterRange range = mCanonical.queryParameter(11, 12); 569 assertNull(range); 570 verify(driver_2_3).queryParameter(eq(11), eq(12), any()); 571 } else { 572 ModelParameterRange range = mCanonical.queryParameter(11, 12); 573 assertNull(range); 574 } 575 } 576 testGlobalCallback_2_0()577 private void testGlobalCallback_2_0() { 578 ISoundTriggerHal.GlobalCallback canonicalCallback = mock( 579 ISoundTriggerHal.GlobalCallback.class); 580 mCanonical.registerCallback(canonicalCallback); 581 // We just care that it doesn't throw. 582 } 583 584 @Test testGlobalCallback()585 public void testGlobalCallback() { 586 testGlobalCallback_2_0(); 587 } 588 589 @Test testLinkToDeath()590 public void testLinkToDeath() throws Exception { 591 IBinder.DeathRecipient canonicalRecipient = mock(IBinder.DeathRecipient.class); 592 when(mHalDriver.linkToDeath(any(), anyLong())).thenReturn(true); 593 mCanonical.linkToDeath(canonicalRecipient); 594 595 ArgumentCaptor<IHwBinder.DeathRecipient> recipientCaptor = ArgumentCaptor.forClass( 596 IHwBinder.DeathRecipient.class); 597 ArgumentCaptor<Long> cookieCaptor = ArgumentCaptor.forClass(Long.class); 598 verify(mHalDriver).linkToDeath(recipientCaptor.capture(), cookieCaptor.capture()); 599 600 recipientCaptor.getValue().serviceDied(cookieCaptor.getValue()); 601 mCanonical.flushCallbacks(); 602 verify(canonicalRecipient).binderDied(); 603 604 mCanonical.unlinkToDeath(canonicalRecipient); 605 verify(mHalDriver).unlinkToDeath(recipientCaptor.getValue()); 606 } 607 608 @Test testInterfaceDescriptor()609 public void testInterfaceDescriptor() throws Exception { 610 when(mHalDriver.interfaceDescriptor()).thenReturn("ABCD"); 611 assertEquals("ABCD", mCanonical.interfaceDescriptor()); 612 verify(mHalDriver).interfaceDescriptor(); 613 } 614 validateCallback_2_0( android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback hwCallback, ISoundTriggerHal.ModelCallback canonicalCallback)615 private void validateCallback_2_0( 616 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback hwCallback, 617 ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception { 618 { 619 final int handle = 85; 620 final int status = 621 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; 622 ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 623 RecognitionEventSys.class); 624 625 hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status), 99); 626 mCanonical.flushCallbacks(); 627 verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture()); 628 RecognitionEventSys lastEvent = eventCaptor.getValue(); 629 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 630 TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent, 631 RecognitionStatus.ABORTED, 632 false); 633 } 634 635 { 636 final int handle = 92; 637 final int status = 638 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS; 639 ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 640 PhraseRecognitionEventSys.class); 641 642 hwCallback.phraseRecognitionCallback( 643 TestUtil.createPhraseRecognitionEvent_2_0(handle, status), 99); 644 mCanonical.flushCallbacks(); 645 verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture()); 646 PhraseRecognitionEventSys lastEvent = eventCaptor.getValue(); 647 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 648 TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent, 649 RecognitionStatus.SUCCESS, false); 650 } 651 verifyNoMoreInteractions(canonicalCallback); 652 clearInvocations(canonicalCallback); 653 } 654 validateCallback_2_1( android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback hwCallback, ISoundTriggerHal.ModelCallback canonicalCallback)655 private void validateCallback_2_1( 656 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback hwCallback, 657 ISoundTriggerHal.ModelCallback canonicalCallback) throws Exception { 658 { 659 final int handle = 85; 660 final int status = 661 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; 662 ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 663 RecognitionEventSys.class); 664 665 hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status), 666 99); 667 mCanonical.flushCallbacks(); 668 verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture()); 669 RecognitionEventSys lastEvent = eventCaptor.getValue(); 670 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 671 TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent, 672 RecognitionStatus.ABORTED, 673 false); 674 } 675 676 { 677 final int handle = 87; 678 final int status = 3; // FORCED; 679 ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 680 RecognitionEventSys.class); 681 682 hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status), 683 99); 684 mCanonical.flushCallbacks(); 685 verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture()); 686 RecognitionEventSys lastEvent = eventCaptor.getValue(); 687 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 688 TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent, 689 RecognitionStatus.FORCED, 690 true); 691 } 692 693 { 694 final int handle = 92; 695 final int status = 696 android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS; 697 ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 698 PhraseRecognitionEventSys.class); 699 700 hwCallback.phraseRecognitionCallback_2_1( 701 TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99); 702 mCanonical.flushCallbacks(); 703 verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture()); 704 PhraseRecognitionEventSys lastEvent = eventCaptor.getValue(); 705 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 706 TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent, 707 RecognitionStatus.SUCCESS, false); 708 } 709 710 { 711 final int handle = 102; 712 final int status = 3; // FORCED; 713 ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass( 714 PhraseRecognitionEventSys.class); 715 716 hwCallback.phraseRecognitionCallback_2_1( 717 TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99); 718 mCanonical.flushCallbacks(); 719 verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture()); 720 PhraseRecognitionEventSys lastEvent = eventCaptor.getValue(); 721 assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0); 722 TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent, 723 RecognitionStatus.FORCED, true); 724 } 725 verifyNoMoreInteractions(canonicalCallback); 726 clearInvocations(canonicalCallback); 727 } 728 } 729