1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.recognitionservice.service;
18 
19 import android.app.AppOpsManager;
20 import android.content.Intent;
21 import android.media.MediaRecorder;
22 import android.os.Bundle;
23 import android.os.RemoteException;
24 import android.speech.RecognitionService;
25 import android.speech.RecognizerIntent;
26 import android.util.Log;
27 
28 import java.io.File;
29 import java.io.IOException;
30 
31 /**
32  * Implementation of {@link RecognitionService} used in the tests.
33  */
34 public class CtsVoiceRecognitionService extends RecognitionService {
35 
36     private final String TAG = "CtsVoiceRecognitionService";
37 
38     private MediaRecorder mMediaRecorder;
39     private File mOutputFile;
40 
41     @Override
onCancel(Callback listener)42     protected void onCancel(Callback listener) {
43         // No-op.
44     }
45 
46     @Override
onStopListening(Callback listener)47     protected void onStopListening(Callback listener) {
48         // No-op.
49     }
50 
51     @Override
onStartListening(Intent recognizerIntent, Callback listener)52     protected void onStartListening(Intent recognizerIntent, Callback listener) {
53         Log.d(TAG, "onStartListening");
54         if (listener != null) {
55             // We only want to make sure onStartListening() is called successfully, so it returns
56             // empty bundle here.
57             try {
58                 listener.results(Bundle.EMPTY);
59                 Log.i(TAG, "Invoked #results");
60             } catch (RemoteException e) {
61                 Log.e(TAG, "Failed to invoke #results", e);
62             }
63         }
64         mediaRecorderReady();
65         blameCameraPermission(recognizerIntent, listener.getCallingUid());
66         try {
67             mMediaRecorder.prepare();
68             mMediaRecorder.start();
69         } catch (IOException e) {
70             // We focus on the open mic behavior, wedon't need to real record and save to the file.
71             // Because we don't set the output the output file. The IOException occurred when start.
72             // We catch this and reset the media record.
73             e.printStackTrace();
74             mMediaRecorder.release();
75             mMediaRecorder = null;
76         }
77     }
78 
79     @Override
onDestroy()80     public void onDestroy() {
81         Log.d(TAG, "onDestroy");
82         stopRecord();
83         super.onDestroy();
84     }
85 
86     // RecognitionService try to blame non-mic permission
blameCameraPermission(Intent recognizerIntent, int callingPackageUid)87     private void blameCameraPermission(Intent recognizerIntent, int callingPackageUid) {
88         final String callingPackage =
89                 recognizerIntent.getStringExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE);
90         final AppOpsManager appOpsManager = getSystemService(AppOpsManager.class);
91         appOpsManager.noteProxyOpNoThrow(AppOpsManager.OPSTR_CAMERA, callingPackage,
92                 callingPackageUid, /*attributionTag*/ null, /*message*/ null);
93     }
94 
mediaRecorderReady()95     private void mediaRecorderReady() {
96         mMediaRecorder = new MediaRecorder();
97         mOutputFile = new File(getExternalCacheDir(), "test.3gp");
98         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
99         mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
100         mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
101         mMediaRecorder.setOutputFile(mOutputFile);
102     }
103 
stopRecord()104     private void stopRecord() {
105         if (mMediaRecorder != null) {
106             mMediaRecorder.stop();
107             mMediaRecorder.release();
108             mMediaRecorder = null;
109         }
110         if (mOutputFile != null && mOutputFile.exists()) {
111             mOutputFile.delete();
112         }
113     }
114 }
115