add SoundTrigger HAL 2.3 per model parameter apis

add support for model parameter control APIs with THRESHOLD_FACTOR
as the first supported parameter

Bug: 141929369
Test: Tested manually with test app and confirmed with GTS test
gts-tradefed run gts-dev -m GtsAssistIntentTestCases
Change-Id: I06874fcf2ae2ef8796e7c52c4475252e8a026e2c
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 735b9a1..198b4c3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,11 +16,14 @@
 
 package com.android.server.soundtrigger;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent;
 import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
@@ -28,6 +31,7 @@
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
@@ -605,6 +609,67 @@
         return STATUS_ERROR;
     }
 
+    int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
+        synchronized (mLock) {
+            MetricsLogger.count(mContext, "sth_set_parameter", 1);
+            if (modelId == null || mModule == null) {
+                return SoundTrigger.STATUS_ERROR;
+            }
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null) {
+                Slog.w(TAG, "SetParameter: Invalid model id:" + modelId);
+                return SoundTrigger.STATUS_BAD_VALUE;
+            }
+            if (!modelData.isModelLoaded()) {
+                Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelId);
+                return SoundTrigger.STATUS_BAD_VALUE;
+            }
+
+            return mModule.setParameter(modelData.getHandle(), modelParam, value);
+        }
+    }
+
+    int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
+            throws UnsupportedOperationException, IllegalArgumentException {
+        synchronized (mLock) {
+            MetricsLogger.count(mContext, "sth_get_parameter", 1);
+            if (mModule == null) {
+                throw new UnsupportedOperationException("SoundTriggerModule not initialized");
+            }
+
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null) {
+                throw new IllegalArgumentException("Invalid model id:" + modelId);
+            }
+            if (!modelData.isModelLoaded()) {
+                throw new UnsupportedOperationException("Given model is not loaded:" + modelId);
+            }
+
+            return mModule.getParameter(modelData.getHandle(), modelParam);
+        }
+    }
+
+    @Nullable
+    ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
+        synchronized (mLock) {
+            MetricsLogger.count(mContext, "sth_query_parameter", 1);
+            if (mModule == null) {
+                return null;
+            }
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null) {
+                Slog.w(TAG, "queryParameter: Invalid model id:" + modelId);
+                return null;
+            }
+            if (!modelData.isModelLoaded()) {
+                Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelId);
+                return null;
+            }
+
+            return mModule.queryParameter(modelData.getHandle(), modelParam);
+        }
+    }
+
     //---- SoundTrigger.StatusListener methods
     @Override
     public void onRecognition(RecognitionEvent event) {
@@ -653,15 +718,15 @@
         }
         ModelData model = getModelDataForLocked(event.soundModelHandle);
         if (model == null || !model.isGenericModel()) {
-            Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
-                    event.soundModelHandle);
+            Slog.w(TAG, "Generic recognition event: Model does not exist for handle: "
+                    + event.soundModelHandle);
             return;
         }
 
         IRecognitionStatusCallback callback = model.getCallback();
         if (callback == null) {
-            Slog.w(TAG, "Generic recognition event: Null callback for model handle: " +
-                    event.soundModelHandle);
+            Slog.w(TAG, "Generic recognition event: Null callback for model handle: "
+                    + event.soundModelHandle);
             return;
         }
 
@@ -678,8 +743,8 @@
 
         RecognitionConfig config = model.getRecognitionConfig();
         if (config == null) {
-            Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " +
-                    event.soundModelHandle);
+            Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: "
+                    + event.soundModelHandle);
             return;
         }
 
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 1dd3972..96d2df1 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -22,7 +22,9 @@
 import static android.content.pm.PackageManager.GET_META_DATA;
 import static android.content.pm.PackageManager.GET_SERVICES;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_BAD_VALUE;
 import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_NO_INIT;
 import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
 import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY;
 import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT;
@@ -39,9 +41,11 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
 import android.hardware.soundtrigger.SoundTrigger.SoundModel;
@@ -683,6 +687,101 @@
                 return properties;
             }
         }
+
+        @Override
+        public int setParameter(ParcelUuid soundModelId,
+                @ModelParams int modelParam, int value) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (!isInitialized()) return STATUS_NO_INIT;
+            if (DEBUG) {
+                Slog.d(TAG, "setParameter(): id=" + soundModelId
+                        + ", param=" + modelParam
+                        + ", value=" + value);
+            }
+
+            sEventLogger.log(new SoundTriggerLogger.StringEvent(
+                    "setParameter(): id=" + soundModelId
+                            + ", param=" + modelParam
+                            + ", value=" + value));
+
+            synchronized (mLock) {
+                SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+                if (soundModel == null) {
+                    Slog.e(TAG, soundModelId + " is not loaded. Loaded models: "
+                            + mLoadedModels.toString());
+
+                    sEventLogger.log(new SoundTriggerLogger.StringEvent("setParameter(): "
+                            + soundModelId + " is not loaded"));
+
+                    return STATUS_BAD_VALUE;
+                }
+
+                return mSoundTriggerHelper.setParameter(soundModel.uuid, modelParam, value);
+            }
+        }
+
+        @Override
+        public int getParameter(@NonNull ParcelUuid soundModelId,
+                @ModelParams int modelParam)
+                throws UnsupportedOperationException, IllegalArgumentException {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (!isInitialized()) {
+                throw new UnsupportedOperationException("SoundTriggerHelper not initialized");
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "getParameter(): id=" + soundModelId
+                        + ", param=" + modelParam);
+            }
+
+            sEventLogger.log(new SoundTriggerLogger.StringEvent(
+                    "getParameter(): id=" + soundModelId
+                            + ", param=" + modelParam));
+
+            synchronized (mLock) {
+                SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+                if (soundModel == null) {
+                    Slog.e(TAG, soundModelId + " is not loaded");
+
+                    sEventLogger.log(new SoundTriggerLogger.StringEvent("getParameter(): "
+                            + soundModelId + " is not loaded"));
+
+                    throw new IllegalArgumentException("sound model is not loaded");
+                }
+
+                return mSoundTriggerHelper.getParameter(soundModel.uuid, modelParam);
+            }
+        }
+
+        @Override
+        @Nullable
+        public ModelParamRange queryParameter(@NonNull ParcelUuid soundModelId,
+                @ModelParams int modelParam) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (!isInitialized()) return null;
+            if (DEBUG) {
+                Slog.d(TAG, "queryParameter(): id=" + soundModelId
+                        + ", param=" + modelParam);
+            }
+
+            sEventLogger.log(new SoundTriggerLogger.StringEvent(
+                    "queryParameter(): id=" + soundModelId
+                            + ", param=" + modelParam));
+
+            synchronized (mLock) {
+                SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+                if (soundModel == null) {
+                    Slog.e(TAG, soundModelId + " is not loaded");
+
+                    sEventLogger.log(new SoundTriggerLogger.StringEvent(
+                            "queryParameter(): "
+                                    + soundModelId + " is not loaded"));
+
+                    return null;
+                }
+
+                return mSoundTriggerHelper.queryParameter(soundModel.uuid, modelParam);
+            }
+        }
     }
 
     /**