/* * Copyright (C) 2014 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 android.hardware.soundtrigger; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import android.content.Context; import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; import android.media.soundtrigger.SoundTriggerManager; import android.os.ParcelUuid; import android.os.ServiceManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.app.ISoundTriggerService; import java.io.DataOutputStream; import java.net.InetAddress; import java.net.Socket; import java.util.ArrayList; import java.util.HashSet; import java.util.Random; import java.util.UUID; import org.mockito.MockitoAnnotations; public class GenericSoundModelTest extends AndroidTestCase { static final int MSG_DETECTION_ERROR = -1; static final int MSG_DETECTION_RESUME = 0; static final int MSG_DETECTION_PAUSE = 1; static final int MSG_KEYPHRASE_TRIGGER = 2; static final int MSG_GENERIC_TRIGGER = 4; private Random random = new Random(); private HashSet loadedModelUuids; private ISoundTriggerService soundTriggerService; private SoundTriggerManager soundTriggerManager; @Override public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); Context context = getContext(); soundTriggerService = ISoundTriggerService.Stub.asInterface( ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE)); soundTriggerManager = (SoundTriggerManager) context.getSystemService( Context.SOUND_TRIGGER_SERVICE); loadedModelUuids = new HashSet(); } @Override public void tearDown() throws Exception { for (UUID modelUuid : loadedModelUuids) { soundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid)); } super.tearDown(); } GenericSoundModel new_sound_model() { // Create sound model byte[] data = new byte[1024]; random.nextBytes(data); UUID modelUuid = UUID.randomUUID(); UUID mVendorUuid = UUID.randomUUID(); return new GenericSoundModel(modelUuid, mVendorUuid, data); } @SmallTest public void testUpdateGenericSoundModel() throws Exception { GenericSoundModel model = new_sound_model(); // Update sound model soundTriggerService.updateSoundModel(model); loadedModelUuids.add(model.uuid); // Confirm it was updated GenericSoundModel returnedModel = soundTriggerService.getSoundModel(new ParcelUuid(model.uuid)); assertEquals(model, returnedModel); } @SmallTest public void testDeleteGenericSoundModel() throws Exception { GenericSoundModel model = new_sound_model(); // Update sound model soundTriggerService.updateSoundModel(model); loadedModelUuids.add(model.uuid); // Delete sound model soundTriggerService.deleteSoundModel(new ParcelUuid(model.uuid)); loadedModelUuids.remove(model.uuid); // Confirm it was deleted GenericSoundModel returnedModel = soundTriggerService.getSoundModel(new ParcelUuid(model.uuid)); assertEquals(null, returnedModel); } @LargeTest public void testStartStopGenericSoundModel() throws Exception { GenericSoundModel model = new_sound_model(); boolean captureTriggerAudio = true; boolean allowMultipleTriggers = true; RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, null, null); TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback()); // Update and start sound model recognition soundTriggerService.updateSoundModel(model); loadedModelUuids.add(model.uuid); int r = soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback, config); assertEquals("Could Not Start Recognition with code: " + r, android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); // Stop recognition r = soundTriggerService.stopRecognition(new ParcelUuid(model.uuid), spyCallback); assertEquals("Could Not Stop Recognition with code: " + r, android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); } @LargeTest public void testTriggerGenericSoundModel() throws Exception { GenericSoundModel model = new_sound_model(); boolean captureTriggerAudio = true; boolean allowMultipleTriggers = true; RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, null, null); TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback()); // Update and start sound model soundTriggerService.updateSoundModel(model); loadedModelUuids.add(model.uuid); soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback, config); // Send trigger to stub HAL Socket socket = new Socket(InetAddress.getLocalHost(), 14035); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); out.writeBytes("trig " + model.uuid.toString() + "\r\n"); out.flush(); socket.close(); // Verify trigger was received verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any()); } /** * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping * recognition. Intended to find unexpected errors that occur in unexpected states. */ @LargeTest public void testFuzzGenericSoundModel() throws Exception { int numModels = 2; final int STATUS_UNLOADED = 0; final int STATUS_LOADED = 1; final int STATUS_STARTED = 2; class ModelInfo { int status; GenericSoundModel model; public ModelInfo(GenericSoundModel model, int status) { this.status = status; this.model = model; } } Random predictableRandom = new Random(100); ArrayList modelInfos = new ArrayList(); for(int i=0; i