diff options
| author | 2016-02-21 18:10:28 -0800 | |
|---|---|---|
| committer | 2016-02-22 15:19:44 -0800 | |
| commit | 2d1de78a4c8fc224329a9622c9326e42a42ddadd (patch) | |
| tree | 6c5bc935e1007db0de7ed99ba877fb311e0fe48f | |
| parent | 9a08f827a4f8ac333402e22e5d45228abe8d98fa (diff) | |
Unload logic for generic and keyphrase sound models.
When delete is called, now the STH unloads the corresponding models.
Fix bug with keyphrase where a delete call didn't unload (or stop)
the keyphrase model.
Bug: 27279380
Change-Id: Ia34f713d2aecef4102c0f0ccc57b8d2e5febe4bb
6 files changed, 162 insertions, 22 deletions
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index b4c4bf8b5ef3..7ee7423538a0 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -199,6 +199,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } modelData.setHandle(handle[0]); modelData.setLoaded(); + Slog.d(TAG, "Generic sound model loaded with handle:" + handle[0]); } modelData.setCallback(callback); modelData.setRecognitionConfig(recognitionConfig); @@ -227,7 +228,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { synchronized (mLock) { if (DBG) { - Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId + Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId + " soundModel=" + soundModel + ", listener=" + listener.asBinder() + ", recognitionConfig=" + recognitionConfig); Slog.d(TAG, "moduleProperties=" + mModuleProperties); @@ -243,13 +244,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } if (mModuleProperties == null) { - Slog.w(TAG, "Attempting startRecognition without the capability"); + Slog.w(TAG, "Attempting startKeyphraseRecognition without the capability"); return STATUS_ERROR; } if (mModule == null) { mModule = SoundTrigger.attachModule(mModuleProperties.id, this, null); if (mModule == null) { - Slog.w(TAG, "startRecognition cannot attach to sound trigger module"); + Slog.w(TAG, "startKeyphraseRecognition cannot attach to sound trigger module"); return STATUS_ERROR; } } @@ -348,26 +349,29 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } if (currentCallback == null || !modelData.isModelStarted()) { - // startRecognition hasn't been called or it failed. - Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition"); + // startGenericRecognition hasn't been called or it failed. + Slog.w(TAG, "Attempting stopGenericRecognition without a successful" + + " startGenericRecognition"); return STATUS_ERROR; } if (currentCallback.asBinder() != listener.asBinder()) { // We don't allow a different listener to stop the recognition than the one // that started it. - Slog.w(TAG, "Attempting stopRecognition for another recognition"); + Slog.w(TAG, "Attempting stopGenericRecognition for another recognition"); return STATUS_ERROR; } - int status = stopGenericRecognitionLocked(modelData, false /* don't notify for synchronous calls */); + int status = stopGenericRecognitionLocked(modelData, + false /* don't notify for synchronous calls */); if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "stopGenericRecognition failed: " + status); return status; } // We leave the sound model loaded but not started, this helps us when we start // back. // Also clear the internal state once the recognition has been stopped. - modelData.clearState(); + modelData.setLoaded(); modelData.clearCallback(); if (!computeRecognitionRunning()) { internalClearGlobalStateLocked(); @@ -471,6 +475,66 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return mModuleProperties; } + int unloadKeyphraseSoundModel(int keyphraseId) { + if (mModule == null || mCurrentKeyphraseModelHandle == INVALID_VALUE) { + return STATUS_ERROR; + } + if (mKeyphraseId != keyphraseId) { + Slog.w(TAG, "Given sound model is not the one loaded."); + return STATUS_ERROR; + } + + synchronized (mLock) { + // Stop recognition if it's the current one. + mRequested = false; + int status = updateRecognitionLocked(false /* don't notify */); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status); + } + + status = mModule.unloadSoundModel(mCurrentKeyphraseModelHandle); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status); + } + internalClearKeyphraseSoundModelLocked(); + return status; + } + } + + int unloadGenericSoundModel(UUID modelId) { + if (modelId == null || mModule == null) { + return STATUS_ERROR; + } + ModelData modelData = mGenericModelDataMap.get(modelId); + if (modelData == null) { + Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId); + return STATUS_ERROR; + } + synchronized (mLock) { + if (!modelData.isModelLoaded()) { + // Nothing to do here. + Slog.i(TAG, "Unload: Given generic model is not loaded:" + modelId); + return STATUS_OK; + } + if (modelData.isModelStarted()) { + int status = stopGenericRecognitionLocked(modelData, + false /* don't notify for synchronous calls */); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "stopGenericRecognition failed: " + status); + } + } + + int status = mModule.unloadSoundModel(modelData.getHandle()); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status); + Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded."); + } + mGenericModelDataMap.remove(modelId); + if (DBG) dumpGenericModelState(); + return status; + } + } + //---- SoundTrigger.StatusListener methods @Override public void onRecognition(RecognitionEvent event) { @@ -913,6 +977,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } } else { + Slog.i(TAG, "startRecognition successful."); modelData.setStarted(); // Notify of resume if needed. if (notify) { @@ -923,6 +988,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } } + if (DBG) dumpGenericModelState(); return status; } @@ -951,9 +1017,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } } + if (DBG) dumpGenericModelState(); return status; } + private void dumpGenericModelState() { + for (UUID modelId : mGenericModelDataMap.keySet()) { + ModelData modelData = mGenericModelDataMap.get(modelId); + Slog.i(TAG, "Model :" + modelData.toString()); + } + } + // Computes whether we have any recognition running at all (voice or generic). Sets // the mRecognitionRunning variable with the result. private boolean computeRecognitionRunning() { @@ -1069,5 +1143,18 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { synchronized RecognitionConfig getRecognitionConfig() { return mRecognitionConfig; } + + String stateToString() { + switch(mModelState) { + case MODEL_NOTLOADED: return "NOT_LOADED"; + case MODEL_LOADED: return "LOADED"; + case MODEL_STARTED: return "STARTED"; + } + return "Unknown state"; + } + + public String toString() { + return "Handle: " + mModelHandle + "ModelState: " + stateToString(); + } } } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java index 772287624f6a..113431f2de7e 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java @@ -75,5 +75,7 @@ public abstract class SoundTriggerInternal { public abstract ModuleProperties getModuleProperties(); + public abstract int unloadKeyphraseModel(int keyphaseId); + public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index 251f3146f8cc..a4c1210ba188 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -122,10 +122,10 @@ public class SoundTriggerService extends SystemService { public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback, RecognitionConfig config) { enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); + if (!isInitialized()) return STATUS_ERROR; if (DEBUG) { Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid); } - if (!isInitialized()) return STATUS_ERROR; GenericSoundModel model = getSoundModel(parcelUuid); if (model == null) { @@ -173,6 +173,8 @@ public class SoundTriggerService extends SystemService { if (DEBUG) { Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId); } + // Unload the model if it is loaded. + mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid()); mDbHelper.deleteGenericSoundModel(soundModelId.getUuid()); } } @@ -216,6 +218,12 @@ public class SoundTriggerService extends SystemService { } @Override + public int unloadKeyphraseModel(int keyphraseId) { + if (!isInitialized()) return STATUS_ERROR; + return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId); + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!isInitialized()) return; mSoundTriggerHelper.dump(fd, pw, args); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 4a54643b3cf5..6ab0b998bd6c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -760,6 +760,10 @@ public class VoiceInteractionManagerService extends SystemService { final long caller = Binder.clearCallingIdentity(); boolean deleted = false; try { + int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId); + if (unloadStatus != SoundTriggerInternal.STATUS_OK) { + Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus); + } deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR; } finally { diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml index a72b3ddb7c0c..dc4cdb59b8db 100644 --- a/tests/SoundTriggerTestApp/AndroidManifest.xml +++ b/tests/SoundTriggerTestApp/AndroidManifest.xml @@ -2,10 +2,12 @@ package="com.android.test.soundtrigger"> <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" /> + <uses-permission android:name="android.permission.WAKE_LOCk" /> <application> <activity android:name="TestSoundTriggerActivity" android:label="SoundTrigger Test Application" + android:screenOrientation="portrait" android:theme="@android:style/Theme.Material"> <!-- <intent-filter> diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java index 3149783506de..95e2dcffe9c4 100644 --- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java +++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java @@ -28,6 +28,8 @@ import android.media.soundtrigger.SoundTriggerManager; import android.text.Editable; import android.text.method.ScrollingMovementMethod; import android.os.Bundle; +import android.os.Handler; +import android.os.PowerManager; import android.os.UserManager; import android.util.Log; import android.view.View; @@ -54,6 +56,8 @@ public class TestSoundTriggerActivity extends Activity { private TextView mDebugView = null; private int mSelectedModelId = 1; private ScrollView mScrollView = null; + private PowerManager.WakeLock mScreenWakelock; + private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { @@ -66,6 +70,7 @@ public class TestSoundTriggerActivity extends Activity { mDebugView.setMovementMethod(new ScrollingMovementMethod()); mSoundTriggerUtil = new SoundTriggerUtil(this); mRandom = new Random(); + mHandler = new Handler(); } private void postMessage(String msg) { @@ -85,24 +90,43 @@ public class TestSoundTriggerActivity extends Activity { }); } - private UUID getSelectedUuid() { + private synchronized UUID getSelectedUuid() { if (mSelectedModelId == 2) return mModelUuid2; if (mSelectedModelId == 3) return mModelUuid3; return mModelUuid1; // Default. } - private void setDetector(SoundTriggerDetector detector) { - if (mSelectedModelId == 2) mDetector2 = detector; - if (mSelectedModelId == 3) mDetector3 = detector; + private synchronized void setDetector(SoundTriggerDetector detector) { + if (mSelectedModelId == 2) { + mDetector2 = detector; + return; + } + if (mSelectedModelId == 3) { + mDetector3 = detector; + return; + } mDetector1 = detector; } - private SoundTriggerDetector getDetector() { + private synchronized SoundTriggerDetector getDetector() { if (mSelectedModelId == 2) return mDetector2; if (mSelectedModelId == 3) return mDetector3; return mDetector1; } + private void screenWakeup() { + PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE)); + if (mScreenWakelock == null) { + mScreenWakelock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "TAG"); + } + mScreenWakelock.acquire(); + } + + private void screenRelease() { + PowerManager pm = ((PowerManager)getSystemService(POWER_SERVICE)); + mScreenWakelock.release(); + } + /** * Called when the user clicks the enroll button. * Performs a fresh enrollment. @@ -139,7 +163,7 @@ public class TestSoundTriggerActivity extends Activity { Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show(); return; } - boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid1); + boolean status = mSoundTriggerUtil.deleteSoundModel(modelUuid); if (status) { Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid, Toast.LENGTH_SHORT) @@ -204,22 +228,28 @@ public class TestSoundTriggerActivity extends Activity { } } - public void onRadioButtonClicked(View view) { + public synchronized void onRadioButtonClicked(View view) { // Is the button now checked? boolean checked = ((RadioButton) view).isChecked(); // Check which radio button was clicked switch(view.getId()) { case R.id.model_one: - if (checked) mSelectedModelId = 1; - postMessage("Selected model one."); + if (checked) { + mSelectedModelId = 1; + postMessage("Selected model one."); + } break; case R.id.model_two: - if (checked) mSelectedModelId = 2; - postMessage("Selected model two."); + if (checked) { + mSelectedModelId = 2; + postMessage("Selected model two."); + } break; case R.id.model_three: - if (checked) mSelectedModelId = 3; - postMessage("Selected model three."); + if (checked) { + mSelectedModelId = 3; + postMessage("Selected model three."); + } break; } } @@ -232,6 +262,13 @@ public class TestSoundTriggerActivity extends Activity { public void onDetected(SoundTriggerDetector.EventPayload event) { postMessage("onDetected(): " + eventPayloadToString(event)); + screenWakeup(); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + screenRelease(); + } + }, 1000L); } public void onError() { |