1a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra/*
2a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * Copyright (C) 2014 The Android Open Source Project
3a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra *
4a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * Licensed under the Apache License, Version 2.0 (the "License");
5a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * you may not use this file except in compliance with the License.
6a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * You may obtain a copy of the License at
7a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra *
8a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra *      http://www.apache.org/licenses/LICENSE-2.0
9a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra *
10a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * Unless required by applicable law or agreed to in writing, software
11a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * distributed under the License is distributed on an "AS IS" BASIS,
12a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * See the License for the specific language governing permissions and
14a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * limitations under the License.
15a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra */
16a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
17a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishrapackage com.android.server.soundtrigger;
183fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishraimport static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
19a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
20a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.content.Context;
21a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.content.pm.PackageManager;
22a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.Manifest;
23a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.hardware.soundtrigger.IRecognitionStatusCallback;
24a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.hardware.soundtrigger.SoundTrigger;
25c722ec4105f7a4733a22fb9004e784347ee36663Arunesh Mishraimport android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
26a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
2755a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishraimport android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
28a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
29a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.os.Parcel;
30a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.os.ParcelUuid;
31a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.os.RemoteException;
32a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport android.util.Slog;
33a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
34a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport com.android.server.SystemService;
35a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport com.android.internal.app.ISoundTriggerService;
36a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
37a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport java.io.FileDescriptor;
38a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport java.io.PrintWriter;
39a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishraimport java.util.UUID;
40a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
41a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra/**
42a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * A single SystemService to manage all sound/voice-based sound models on the DSP.
43a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * This services provides apis to manage sound trigger-based sound models via
44a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * the ISoundTriggerService interface. This class also publishes a local interface encapsulating
45a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * the functionality provided by {@link SoundTriggerHelper} for use by
46a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * {@link VoiceInteractionManagerService}.
47a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra *
48a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra * @hide
49a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra */
50a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishrapublic class SoundTriggerService extends SystemService {
513fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    private static final String TAG = "SoundTriggerService";
523fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    private static final boolean DEBUG = true;
53a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
54a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    final Context mContext;
55a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    private final SoundTriggerServiceStub mServiceStub;
56a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    private final LocalSoundTriggerService mLocalSoundTriggerService;
57a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    private SoundTriggerDbHelper mDbHelper;
583fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    private SoundTriggerHelper mSoundTriggerHelper;
59a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
60a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public SoundTriggerService(Context context) {
61a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        super(context);
62a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        mContext = context;
63a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        mServiceStub = new SoundTriggerServiceStub();
64a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        mLocalSoundTriggerService = new LocalSoundTriggerService(context);
65a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
66a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
67a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    @Override
68a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public void onStart() {
69a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        publishBinderService(Context.SOUND_TRIGGER_SERVICE, mServiceStub);
70a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
71a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
72a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
73a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    @Override
74a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public void onBootPhase(int phase) {
75a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        if (PHASE_SYSTEM_SERVICES_READY == phase) {
763fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            initSoundTriggerHelper();
773fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            mLocalSoundTriggerService.setSoundTriggerHelper(mSoundTriggerHelper);
78a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
79a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            mDbHelper = new SoundTriggerDbHelper(mContext);
80a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
81a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
82a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
83a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    @Override
84a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public void onStartUser(int userHandle) {
85a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
86a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
87a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    @Override
88a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public void onSwitchUser(int userHandle) {
89a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
90a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
913fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    private synchronized void initSoundTriggerHelper() {
923fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        if (mSoundTriggerHelper == null) {
933fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            mSoundTriggerHelper = new SoundTriggerHelper(mContext);
943fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        }
953fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    }
963fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra
973fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    private synchronized boolean isInitialized() {
983fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        if (mSoundTriggerHelper == null ) {
993fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            Slog.e(TAG, "SoundTriggerHelper not initialized.");
1003fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return false;
1013fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        }
1023fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        return true;
1033fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra    }
1043fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra
105a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
106a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
107a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
108a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                throws RemoteException {
109a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            try {
110a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                return super.onTransact(code, data, reply, flags);
111a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            } catch (RuntimeException e) {
112a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                // The activity manager only throws security exceptions, so let's
113a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                // log all others.
114a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                if (!(e instanceof SecurityException)) {
115a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                    Slog.wtf(TAG, "SoundTriggerService Crash", e);
116a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                }
117a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                throw e;
118a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
119a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
120a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
121a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
1223fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
1233fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                RecognitionConfig config) {
124a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
1252d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra            if (!isInitialized()) return STATUS_ERROR;
126a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            if (DEBUG) {
127a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
128a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
1293fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra
1303fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            GenericSoundModel model = getSoundModel(parcelUuid);
1313fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (model == null) {
1323fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                Slog.e(TAG, "Null model in database for id: " + parcelUuid);
1333fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                return STATUS_ERROR;
1343fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            }
1353fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra
1363fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
1373fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                    callback, config);
138a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
139a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
140a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
1413fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        public int stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
142a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
143a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            if (DEBUG) {
144a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
145a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
1463fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (!isInitialized()) return STATUS_ERROR;
1473fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return mSoundTriggerHelper.stopGenericRecognition(parcelUuid.getUuid(), callback);
148a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
149a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
150a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
151c722ec4105f7a4733a22fb9004e784347ee36663Arunesh Mishra        public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
152a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
153a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            if (DEBUG) {
154a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
155a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
1563fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(
1573fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                    soundModelId.getUuid());
158a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            return model;
159a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
160a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
161a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
162c722ec4105f7a4733a22fb9004e784347ee36663Arunesh Mishra        public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
163a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
164a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            if (DEBUG) {
165a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
166a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
167c722ec4105f7a4733a22fb9004e784347ee36663Arunesh Mishra            mDbHelper.updateGenericSoundModel(soundModel);
168a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
169a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
170a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
171a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        public void deleteSoundModel(ParcelUuid soundModelId) {
172a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
173a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            if (DEBUG) {
174a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
175a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            }
1762d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra            // Unload the model if it is loaded.
1772d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra            mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
178c722ec4105f7a4733a22fb9004e784347ee36663Arunesh Mishra            mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
179a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
180a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
181a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
182a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    public final class LocalSoundTriggerService extends SoundTriggerInternal {
183a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        private final Context mContext;
184a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        private SoundTriggerHelper mSoundTriggerHelper;
185a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
186a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        LocalSoundTriggerService(Context context) {
187a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            mContext = context;
188a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
189a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
1903fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        synchronized void setSoundTriggerHelper(SoundTriggerHelper helper) {
1913fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            mSoundTriggerHelper = helper;
192a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
193a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
194a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
195a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
196a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
1973fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (!isInitialized()) return STATUS_ERROR;
1983fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel, listener,
199a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                    recognitionConfig);
200a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
201a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
202a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
2033fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        public synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
2043fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (!isInitialized()) return STATUS_ERROR;
2053fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
206a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
207a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
208a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        @Override
20955a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishra        public ModuleProperties getModuleProperties() {
2103fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (!isInitialized()) return null;
21155a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishra            return mSoundTriggerHelper.getModuleProperties();
21255a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishra        }
21355a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishra
21455a9b0089c12dd657a8dc8551c79cf3e0f25d7e4Arunesh Mishra        @Override
2152d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra        public int unloadKeyphraseModel(int keyphraseId) {
2162d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra            if (!isInitialized()) return STATUS_ERROR;
2172d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra            return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
2182d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra        }
2192d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra
2202d1de78a4c8fc224329a9622c9326e42a42ddaddArunesh Mishra        @Override
221a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2223fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (!isInitialized()) return;
223a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            mSoundTriggerHelper.dump(fd, pw, args);
224a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
2253fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra
2263fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        private synchronized boolean isInitialized() {
2273fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            if (mSoundTriggerHelper == null ) {
2283fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                Slog.e(TAG, "SoundTriggerHelper not initialized.");
2293fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra                return false;
2303fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            }
2313fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra            return true;
2323fff7f5634ca788c1c84b6f1b316819ffd4c7cb2Arunesh Mishra        }
233a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
234a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra
235a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    private void enforceCallingPermission(String permission) {
236a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        if (mContext.checkCallingOrSelfPermission(permission)
237a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra                != PackageManager.PERMISSION_GRANTED) {
238a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra            throw new SecurityException("Caller does not hold the permission " + permission);
239a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra        }
240a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra    }
241a772e5fc062c8de48cb9c1d61755110f6b2e189bArunesh Mishra}
242