Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6784453 authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge changes from topic "st_cts_workaround"

* changes:
  Temporarily allow STHelper without module
  Add module selection APIs to ST
parents 98900be9 9e313513
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.app;

import android.media.permission.Identity;
import android.hardware.soundtrigger.SoundTrigger;
import com.android.internal.app.ISoundTriggerSession;

/**
@@ -43,6 +44,7 @@ interface ISoundTriggerService {
     * to clean-up whenever that happens.
     */
    ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity,
                                            in SoundTrigger.ModuleProperties moduleProperties,
                                            IBinder client);

    /**
@@ -64,5 +66,12 @@ interface ISoundTriggerService {
     */
    ISoundTriggerSession attachAsMiddleman(in Identity middlemanIdentity,
                                           in Identity originatorIdentity,
                                           in SoundTrigger.ModuleProperties moduleProperties,
                                           IBinder client);

    /**
     * Get available underlying SoundTrigger modules to attach to.
     */
    List<SoundTrigger.ModuleProperties> listModuleProperties(in Identity originatorIdentity);

}
+46 −11
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ 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;
import android.media.permission.ClearCallingIdentityContext;
@@ -52,6 +53,7 @@ import com.android.internal.app.ISoundTriggerSession;
import com.android.internal.util.Preconditions;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@@ -92,8 +94,16 @@ public final class SoundTriggerManager {
            originatorIdentity.packageName = ActivityThread.currentOpPackageName();

            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
                mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity,
                List<ModuleProperties> modulePropertiesList = soundTriggerService
                        .listModuleProperties(originatorIdentity);
                if (!modulePropertiesList.isEmpty()) {
                    mSoundTriggerSession = soundTriggerService.attachAsOriginator(
                                                originatorIdentity,
                                                modulePropertiesList.get(0),
                                                mBinderToken);
                } else {
                    mSoundTriggerSession = null;
                }
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
@@ -110,6 +120,9 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Deprecated
    public void updateModel(Model model) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }
        try {
            mSoundTriggerSession.updateSoundModel(model.getGenericSoundModel());
        } catch (RemoteException e) {
@@ -128,6 +141,9 @@ public final class SoundTriggerManager {
    @Nullable
    @Deprecated
    public Model getModel(UUID soundModelId) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }
        try {
            GenericSoundModel model =
                    mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId));
@@ -149,6 +165,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Deprecated
    public void deleteModel(UUID soundModelId) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }

        try {
            mSoundTriggerSession.deleteSoundModel(new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
@@ -176,7 +196,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
            @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return null;
        }

@@ -342,7 +362,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public int loadSoundModel(SoundModel soundModel) {
        if (soundModel == null) {
        if (soundModel == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }

@@ -389,7 +409,9 @@ public final class SoundTriggerManager {
        Preconditions.checkNotNull(soundModelId);
        Preconditions.checkNotNull(detectionService);
        Preconditions.checkNotNull(config);

        if (mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
            return mSoundTriggerSession.startRecognitionForService(new ParcelUuid(soundModelId),
                params, detectionService, config);
@@ -405,7 +427,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public int stopRecognition(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -422,7 +444,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public int unloadSoundModel(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -440,7 +462,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public boolean isRecognitionActive(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return false;
        }
        try {
@@ -475,7 +497,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public int getModelState(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -492,8 +514,10 @@ public final class SoundTriggerManager {
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Nullable
    public SoundTrigger.ModuleProperties getModuleProperties() {

    public ModuleProperties getModuleProperties() {
        if (mSoundTriggerSession == null) {
            return null;
        }
        try {
            return mSoundTriggerSession.getModuleProperties();
        } catch (RemoteException e) {
@@ -520,6 +544,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public int setParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam, int value) {
        if (mSoundTriggerSession == null) {
            return SoundTrigger.STATUS_INVALID_OPERATION;
        }

        try {
            return mSoundTriggerSession.setParameter(new ParcelUuid(soundModelId), modelParam,
                    value);
@@ -543,6 +571,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public int getParameter(@NonNull UUID soundModelId,
            @ModelParams int modelParam) {
        if (mSoundTriggerSession == null) {
            throw new IllegalArgumentException("Sound model is not loaded: "
                            + soundModelId.toString());
        }
        try {
            return mSoundTriggerSession.getParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
@@ -563,6 +595,9 @@ public final class SoundTriggerManager {
    @Nullable
    public ModelParamRange queryParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam) {
        if (mSoundTriggerSession == null) {
            return null;
        }
        try {
            return mSoundTriggerSession.queryParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
+32 −53
Original line number Diff line number Diff line
@@ -56,9 +56,12 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Helper for {@link SoundTrigger} APIs. Supports two types of models:
@@ -74,6 +77,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    static final String TAG = "SoundTriggerHelper";
    static final boolean DBG = false;

    // Module ID if there is no available module to connect to.
    public static final int INVALID_MODULE_ID = -1;

    /**
     * Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
     *      IRecognitionStatusCallback, RecognitionConfig)},
@@ -84,10 +90,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    private static final int INVALID_VALUE = Integer.MIN_VALUE;

    /** The {@link ModuleProperties} for the system, or null if none exists. */
    final ModuleProperties mModuleProperties;

    /** The properties for the DSP module */
    private SoundTriggerModule mModule;
    private final Object mLock = new Object();
    private final Context mContext;
@@ -114,7 +116,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    private PowerSaveModeListener mPowerSaveModeListener;

    private final SoundTriggerModuleProvider mModuleProvider;

    // Handler to process call state changes will delay to allow time for the audio
    // and sound trigger HALs to process the end of call notifications
@@ -123,46 +124,28 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    private static final int MSG_CALL_STATE_CHANGED = 0;
    private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;

    /**
     * Provider interface for retrieving SoundTriggerModule instances
     */
    public interface SoundTriggerModuleProvider {
        /**
         * Populate module properties for all available modules
         *
         * @param modules List of ModuleProperties to be populated
         * @return Status int 0 on success.
         */
        int listModuleProperties(@NonNull ArrayList<SoundTrigger.ModuleProperties> modules);
    // TODO(b/269366605) Temporary solution to query correct moduleProperties
    private final int mModuleId;
    private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
    private final Supplier<List<ModuleProperties>> mModulePropertiesProvider;

        /**
         * Get SoundTriggerModule based on {@link SoundTrigger.ModuleProperties#getId()}
         *
         * @param moduleId Module ID
         * @param statusListener Client listener to be associated with the returned module
         * @return Module associated with moduleId
         */
        SoundTriggerModule getModule(int moduleId, SoundTrigger.StatusListener statusListener);
    }

    SoundTriggerHelper(Context context, SoundTriggerModuleProvider moduleProvider) {
        ArrayList <ModuleProperties> modules = new ArrayList<>();
        mModuleProvider = moduleProvider;
        int status = mModuleProvider.listModuleProperties(modules);
    SoundTriggerHelper(Context context,
            @NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
            int moduleId,
            @NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
        mModuleId = moduleId;
        mContext = context;
        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mModelDataMap = new HashMap<UUID, ModelData>();
        mKeyphraseUuidMap = new HashMap<Integer, UUID>();
        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
            Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
            mModuleProperties = null;
        mModuleProvider = moduleProvider;
        mModulePropertiesProvider = modulePropertiesProvider;
        if (moduleId == INVALID_MODULE_ID) {
            mModule = null;
        } else {
            // TODO: Figure out how to determine which module corresponds to the DSP hardware.
            mModuleProperties = modules.get(0);
            mModule = mModuleProvider.apply(this);
        }

        Looper looper = Looper.myLooper();
        if (looper == null) {
            looper = Looper.getMainLooper();
@@ -245,7 +228,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                        + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
                        + ", recognitionConfig=" + recognitionConfig
                        + ", runInBatterySaverMode=" + runInBatterySaverMode);
                Slog.d(TAG, "moduleProperties=" + mModuleProperties);
                dumpModelStateLocked();
            }

@@ -289,13 +271,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    private int prepareForRecognition(ModelData modelData) {
        if (mModule == null) {
            mModule = mModuleProvider.getModule(mModuleProperties.getId(), this);
        if (mModule == null) {
            Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module");
            return STATUS_ERROR;
        }
        }
        // Load the model if it is not loaded.
        if (!modelData.isModelLoaded()) {
            // Before we try and load this model, we should first make sure that any other
@@ -336,11 +315,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
            int keyphraseId, boolean runInBatterySaverMode) {
        synchronized (mLock) {
            if (mModuleProperties == null) {
                Slog.w(TAG, "Attempting startRecognition without the capability");
                return STATUS_ERROR;
            }

            IRecognitionStatusCallback oldCallback = modelData.getCallback();
            if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
                Slog.w(TAG, "Canceling previous recognition for model id: "
@@ -486,8 +460,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            if (callback == null) {
                return STATUS_ERROR;
            }
            if (mModuleProperties == null || mModule == null) {
                Slog.w(TAG, "Attempting stopRecognition without the capability");
            if (mModule == null) {
                Slog.w(TAG, "Attempting stopRecognition after detach");
                return STATUS_ERROR;
            }

@@ -563,7 +537,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    public ModuleProperties getModuleProperties() {
        return mModuleProperties;
        for (ModuleProperties moduleProperties : mModulePropertiesProvider.get()) {
            if (moduleProperties.getId() == mModuleId) {
                return moduleProperties;
            }
        }
        Slog.e(TAG, "Module properties not found for existing moduleId " + mModuleId);
        return null;
    }

    int unloadKeyphraseSoundModel(int keyphraseId) {
@@ -1027,7 +1007,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            internalClearGlobalStateLocked();
            if (mModule != null) {
                mModule.detach();
                mModule = null;
                mModule = mModuleProvider.apply(this);
            }
        }
    }
@@ -1098,7 +1078,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        synchronized (mLock) {
            pw.print("  module properties=");
            pw.println(mModuleProperties == null ? "null" : mModuleProperties);
            pw.print("  call active=");
            pw.println(mCallActive);
            pw.println("  SoundTrigger Power State=" + mSoundTriggerPowerSaveMode);
@@ -1444,7 +1423,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    // Computes whether we have any recognition running at all (voice or generic). Sets
    // the mRecognitionRequested variable with the result.
    private boolean computeRecognitionRequestedLocked() {
        if (mModuleProperties == null || mModule == null) {
        if (mModule == null) {
            mRecognitionRequested = false;
            return mRecognitionRequested;
        }
+7 −1
Original line number Diff line number Diff line
@@ -26,12 +26,14 @@ 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.media.permission.Identity;
import android.os.IBinder;

import com.android.server.voiceinteraction.VoiceInteractionManagerService;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;

/**
 * Provides a local service for managing voice-related recoginition models. This is primarily used
@@ -46,7 +48,11 @@ public interface SoundTriggerInternal {
    int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
    int STATUS_OK = SoundTrigger.STATUS_OK;

    Session attach(@NonNull IBinder client);
    // Attach to a specific underlying STModule
    Session attach(@NonNull IBinder client, ModuleProperties underlyingModule);

    // Enumerate possible STModules to attach to
    List<ModuleProperties> listModuleProperties(Identity originatorIdentity);

    /**
     * Dumps service-wide information.
+61 −25
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioRecord;
@@ -89,6 +88,7 @@ import com.android.server.utils.EventLogger;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
@@ -215,47 +215,73 @@ public class SoundTriggerService extends SystemService {
        }
    }

    private SoundTriggerHelper newSoundTriggerHelper() {
    private SoundTriggerHelper newSoundTriggerHelper(ModuleProperties moduleProperties) {
        Identity middlemanIdentity = new Identity();
        middlemanIdentity.packageName = ActivityThread.currentOpPackageName();

        Identity originatorIdentity = IdentityContext.getNonNull();

        return new SoundTriggerHelper(mContext,
                new SoundTriggerHelper.SoundTriggerModuleProvider() {
                    @Override
                    public int listModuleProperties(ArrayList<ModuleProperties> modules) {
                        return SoundTrigger.listModulesAsMiddleman(modules, middlemanIdentity,
        ArrayList<ModuleProperties> moduleList = new ArrayList<>();
        SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                        originatorIdentity);
                    }

                    @Override
                    public SoundTriggerModule getModule(int moduleId,
                            SoundTrigger.StatusListener statusListener) {
                        return SoundTrigger.attachModuleAsMiddleman(moduleId, statusListener, null,
                                middlemanIdentity, originatorIdentity);
        // Don't fail existing CTS tests which run without a ST module
        final int moduleId = (moduleProperties != null) ?
                moduleProperties.getId() : SoundTriggerHelper.INVALID_MODULE_ID;

        if (moduleId != SoundTriggerHelper.INVALID_MODULE_ID) {
            if (!moduleList.contains(moduleProperties)) {
                throw new IllegalArgumentException("Invalid module properties");
            }
        }

        return new SoundTriggerHelper(
                mContext,
                (SoundTrigger.StatusListener statusListener) ->
                                        SoundTrigger.attachModuleAsMiddleman(
                                        moduleId, statusListener, null /* handler */,
                                        middlemanIdentity, originatorIdentity),
                moduleId,
                () -> {
                    ArrayList<ModuleProperties> modulePropList = new ArrayList<>();
                    SoundTrigger.listModulesAsMiddleman(modulePropList, middlemanIdentity,
                                                    originatorIdentity);
                    return modulePropList;
                });
    }

    class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
        @Override
        public ISoundTriggerSession attachAsOriginator(Identity originatorIdentity,
        public ISoundTriggerSession attachAsOriginator(@NonNull Identity originatorIdentity,
                @NonNull ModuleProperties moduleProperties,
                @NonNull IBinder client) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
                    originatorIdentity)) {
                return new SoundTriggerSessionStub(client);
                return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
            }
        }

        @Override
        public ISoundTriggerSession attachAsMiddleman(Identity originatorIdentity,
                Identity middlemanIdentity,
        public ISoundTriggerSession attachAsMiddleman(@NonNull Identity originatorIdentity,
                @NonNull Identity middlemanIdentity,
                @NonNull ModuleProperties moduleProperties,
                @NonNull IBinder client) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(mContext,
                    SOUNDTRIGGER_DELEGATE_IDENTITY, middlemanIdentity,
                    originatorIdentity)) {
                return new SoundTriggerSessionStub(client);
                return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
            }
        }

        @Override
        public List<ModuleProperties> listModuleProperties(@NonNull Identity originatorIdentity) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
                    originatorIdentity)) {
                Identity middlemanIdentity = new Identity();
                middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
                ArrayList<ModuleProperties> moduleList = new ArrayList<>();
                SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                                originatorIdentity);
                return moduleList;
            }
        }
    }
@@ -269,8 +295,8 @@ public class SoundTriggerService extends SystemService {
        private final Object mCallbacksLock = new Object();
        private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks = new TreeMap<>();

        SoundTriggerSessionStub(@NonNull IBinder client) {
            mSoundTriggerHelper = newSoundTriggerHelper();
        SoundTriggerSessionStub(@NonNull IBinder client, SoundTriggerHelper soundTriggerHelper) {
            mSoundTriggerHelper = soundTriggerHelper;
            mClient = client;
            mOriginatorIdentity = IdentityContext.getNonNull();
            try {
@@ -1615,8 +1641,18 @@ public class SoundTriggerService extends SystemService {
        }

        @Override
        public Session attach(@NonNull IBinder client) {
            return new SessionImpl(newSoundTriggerHelper(), client);
        public Session attach(@NonNull IBinder client, ModuleProperties underlyingModule) {
            return new SessionImpl(newSoundTriggerHelper(underlyingModule), client);
        }

        @Override
        public List<ModuleProperties> listModuleProperties(Identity originatorIdentity) {
            Identity middlemanIdentity = new Identity();
            middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
            ArrayList<ModuleProperties> moduleList = new ArrayList<>();
            SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                            originatorIdentity);
            return moduleList;
        }

        @Override
Loading