1 /*
2  * Copyright (C) 2015 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 package android.voiceinteraction.common;
17 
18 import android.app.VoiceInteractor.PickOptionRequest.Option;
19 import android.content.LocusId;
20 import android.os.Bundle;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.Log;
24 
25 import java.util.ArrayList;
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.locks.Condition;
29 
30 public class Utils {
31     public enum TestCaseType {
32         COMPLETION_REQUEST_TEST,
33         COMPLETION_REQUEST_CANCEL_TEST,
34         CONFIRMATION_REQUEST_TEST,
35         CONFIRMATION_REQUEST_CANCEL_TEST,
36         ABORT_REQUEST_TEST,
37         ABORT_REQUEST_CANCEL_TEST,
38         PICKOPTION_REQUEST_TEST,
39         PICKOPTION_REQUEST_CANCEL_TEST,
40         COMMANDREQUEST_TEST,
41         COMMANDREQUEST_CANCEL_TEST,
42         SUPPORTS_COMMANDS_TEST
43     }
44 
45     private static final String TAG = Utils.class.getSimpleName();
46 
47     public static final long OPERATION_TIMEOUT_MS = 5000;
48 
49     /** CDD restricts the max size of each successful hotword result is 100 bytes. */
50     public static final int MAX_HOTWORD_DETECTED_RESULT_SIZE = 100;
51 
52     /**
53      * Limits the max value for the hotword offset.
54      *
55      * Note: Must match the definition in
56      * frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java.
57      */
58     public static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE = 60 * 60 * 1000; // 1 hour
59 
60     /**
61      * Limits the max value for the triggered audio channel.
62      *
63      * Note: Must match the definition in
64      * frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java.
65      */
66     public static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63;
67 
68     /** Decide which VoiceInteractionService should be started for testing. */
69     public static final int HOTWORD_DETECTION_SERVICE_NONE = 0;
70     public static final int HOTWORD_DETECTION_SERVICE_BASIC = 1;
71     public static final int HOTWORD_DETECTION_SERVICE_INVALIDATION = 2;
72     public static final int HOTWORD_DETECTION_SERVICE_WITHOUT_ISOLATED_PROCESS = 3;
73     public static final int HOTWORD_DETECTION_SERVICE_WITHIN_ISOLATED_PROCESS = 4;
74 
75     /**
76      * Indicate which test event for testing.
77      *
78      * Note: The VIS is the abbreviation of VoiceInteractionService
79      */
80     public static final int VIS_NORMAL_TEST = 0;
81     public static final int VIS_WITHOUT_MANAGE_HOTWORD_DETECTION_PERMISSION_TEST = 1;
82     public static final int VIS_HOLD_BIND_HOTWORD_DETECTION_PERMISSION_TEST = 2;
83 
84     public static final int HOTWORD_DETECTION_SERVICE_TRIGGER_TEST = 100;
85     public static final int HOTWORD_DETECTION_SERVICE_DSP_ONDETECT_TEST = 101;
86     public static final int HOTWORD_DETECTION_SERVICE_EXTERNAL_SOURCE_ONDETECT_TEST = 102;
87     public static final int HOTWORD_DETECTION_SERVICE_FROM_SOFTWARE_TRIGGER_TEST = 103;
88     public static final int HOTWORD_DETECTION_SERVICE_MIC_ONDETECT_TEST = 104;
89     public static final int HOTWORD_DETECTION_SERVICE_DSP_ONREJECT_TEST = 105;
90     public static final int HOTWORD_DETECTION_SERVICE_PROCESS_DIED_TEST = 106;
91     public static final int HOTWORD_DETECTION_SERVICE_CALL_STOP_RECOGNITION = 107;
92 
93     public static final int HOTWORD_DETECTION_SERVICE_TRIGGER_SUCCESS = 1;
94     public static final int HOTWORD_DETECTION_SERVICE_TRIGGER_ILLEGAL_STATE_EXCEPTION = 2;
95     public static final int HOTWORD_DETECTION_SERVICE_TRIGGER_SECURITY_EXCEPTION = 3;
96     public static final int HOTWORD_DETECTION_SERVICE_TRIGGER_SHARED_MEMORY_NOT_READ_ONLY = 4;
97     public static final int HOTWORD_DETECTION_SERVICE_GET_ERROR = 5;
98 
99     /** Indicate which test scenario for testing. */
100     public static final int HOTWORD_DETECTION_SERVICE_ON_UPDATE_STATE_CRASH = 1;
101 
102     public static final String TESTCASE_TYPE = "testcase_type";
103     public static final String TESTINFO = "testinfo";
104     public static final String BROADCAST_INTENT = "android.intent.action.VOICE_TESTAPP";
105     public static final String TEST_PROMPT = "testprompt";
106     public static final String PICKOPTON_1 = "one";
107     public static final String PICKOPTON_2 = "two";
108     public static final String PICKOPTON_3 = "3";
109     public static final String TEST_COMMAND = "test_command";
110     public static final String TEST_ONCOMMAND_RESULT = "test_oncommand_result";
111     public static final String TEST_ONCOMMAND_RESULT_VALUE = "test_oncommand_result value";
112 
113     public static final String CONFIRMATION_REQUEST_SUCCESS = "confirmation ok";
114     public static final String COMPLETION_REQUEST_SUCCESS = "completion ok";
115     public static final String ABORT_REQUEST_SUCCESS = "abort ok";
116     public static final String PICKOPTION_REQUEST_SUCCESS = "pickoption ok";
117     public static final String COMMANDREQUEST_SUCCESS = "commandrequest ok";
118     public static final String SUPPORTS_COMMANDS_SUCCESS = "supportsCommands ok";
119 
120     public static final String CONFIRMATION_REQUEST_CANCEL_SUCCESS = "confirm cancel ok";
121     public static final String COMPLETION_REQUEST_CANCEL_SUCCESS = "completion canel ok";
122     public static final String ABORT_REQUEST_CANCEL_SUCCESS = "abort cancel ok";
123     public static final String PICKOPTION_REQUEST_CANCEL_SUCCESS = "pickoption  cancel ok";
124     public static final String COMMANDREQUEST_CANCEL_SUCCESS = "commandrequest cancel ok";
125     public static final String TEST_ERROR = "Error In Test:";
126 
127     public static final String PRIVATE_OPTIONS_KEY = "private_key";
128     public static final String PRIVATE_OPTIONS_VALUE = "private_value";
129 
130     public static final String DIRECT_ACTION_EXTRA_KEY = "directActionExtraKey";
131     public static final String DIRECT_ACTION_EXTRA_VALUE = "directActionExtraValue";
132     public static final String DIRECT_ACTION_FILE_NAME = "directActionFileName";
133     public static final String DIRECT_ACTION_FILE_CONTENT = "directActionFileContent";
134     public static final String DIRECT_ACTION_AUTHORITY =
135             "android.voiceinteraction.testapp.fileprovider";
136 
137     public static final String DIRECT_ACTIONS_KEY_CALLBACK = "callback";
138     public static final String DIRECT_ACTIONS_KEY_CANCEL_CALLBACK = "cancelCallback";
139     public static final String DIRECT_ACTIONS_KEY_CONTROL = "control";
140     public static final String DIRECT_ACTIONS_KEY_COMMAND = "command";
141     public static final String DIRECT_ACTIONS_KEY_RESULT = "result";
142     public static final String DIRECT_ACTIONS_KEY_ACTION = "action";
143     public static final String DIRECT_ACTIONS_KEY_ARGUMENTS = "arguments";
144     public static final String DIRECT_ACTIONS_KEY_CLASS = "class";
145 
146     public static final String DIRECT_ACTIONS_SESSION_CMD_PERFORM_ACTION = "performAction";
147     public static final String DIRECT_ACTIONS_SESSION_CMD_PERFORM_ACTION_CANCEL =
148             "performActionCancel";
149     public static final String DIRECT_ACTIONS_SESSION_CMD_DETECT_ACTIONS_CHANGED =
150             "detectActionsChanged";
151     public static final String DIRECT_ACTIONS_SESSION_CMD_GET_ACTIONS = "getActions";
152     public static final String DIRECT_ACTIONS_SESSION_CMD_FINISH = "hide";
153 
154     public static final String DIRECT_ACTIONS_ACTIVITY_CMD_DESTROYED_INTERACTOR =
155             "destroyedInteractor";
156     public static final String DIRECT_ACTIONS_ACTIVITY_CMD_FINISH = "finish";
157     public static final String DIRECT_ACTIONS_ACTIVITY_CMD_INVALIDATE_ACTIONS = "invalidateActions";
158 
159     public static final String DIRECT_ACTIONS_RESULT_PERFORMED = "performed";
160     public static final String DIRECT_ACTIONS_RESULT_CANCELLED = "cancelled";
161     public static final String DIRECT_ACTIONS_RESULT_EXECUTING = "executing";
162 
163     public static final String DIRECT_ACTIONS_ACTION_ID = "actionId";
164     public static final Bundle DIRECT_ACTIONS_ACTION_EXTRAS = new Bundle();
165     static {
DIRECT_ACTIONS_ACTION_EXTRAS.putString(DIRECT_ACTION_EXTRA_KEY, DIRECT_ACTION_EXTRA_VALUE)166         DIRECT_ACTIONS_ACTION_EXTRAS.putString(DIRECT_ACTION_EXTRA_KEY,
167                 DIRECT_ACTION_EXTRA_VALUE);
168     }
169     public static final LocusId DIRECT_ACTIONS_LOCUS_ID = new LocusId("locusId");
170 
171     public static final String SERVICE_NAME =
172             "android.voiceinteraction.service/.MainInteractionService";
173 
174     public static final String HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT_INTENT =
175             "android.intent.action.HOTWORD_DETECTION_SERVICE_TRIGGER_RESULT";
176     public static final String HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT_INTENT =
177             "android.intent.action.HOTWORD_DETECTION_SERVICE_ONDETECT_RESULT";
178     public static final String KEY_SERVICE_TYPE = "serviceType";
179     public static final String KEY_TEST_EVENT = "testEvent";
180     public static final String KEY_TEST_RESULT = "testResult";
181     public static final String KEY_TEST_SCENARIO = "testScenario";
182 
toBundleString(Bundle bundle)183     public static final String toBundleString(Bundle bundle) {
184         if (bundle == null) {
185             return "null_bundle";
186         }
187         StringBuffer buf = new StringBuffer("Bundle[ ");
188         String testType = bundle.getString(TESTCASE_TYPE);
189         boolean empty = true;
190         if (testType != null) {
191             empty = false;
192             buf.append("testcase type = " + testType);
193         }
194         ArrayList<String> info = bundle.getStringArrayList(TESTINFO);
195         if (info != null) {
196             for (String s : info) {
197                 empty = false;
198                 buf.append(s + "\n\t\t");
199             }
200         } else {
201             for (String key : bundle.keySet()) {
202                 empty = false;
203                 Object value = bundle.get(key);
204                 if (value instanceof Bundle) {
205                     value = toBundleString((Bundle) value);
206                 }
207                 buf.append(key).append('=').append(value).append(' ');
208             }
209         }
210         return empty ? "empty_bundle" : buf.append(']').toString();
211     }
212 
toOptionsString(Option[] options)213     public static final String toOptionsString(Option[] options) {
214         StringBuilder sb = new StringBuilder();
215         sb.append("{");
216         for (int i = 0; i < options.length; i++) {
217             if (i >= 1) {
218                 sb.append(", ");
219             }
220             sb.append(options[i].getLabel());
221         }
222         sb.append("}");
223         return sb.toString();
224     }
225 
addErrorResult(final Bundle testinfo, final String msg)226     public static final void addErrorResult(final Bundle testinfo, final String msg) {
227         testinfo.getStringArrayList(testinfo.getString(Utils.TESTCASE_TYPE))
228             .add(TEST_ERROR + " " + msg);
229     }
230 
await(CountDownLatch latch)231     public static boolean await(CountDownLatch latch) {
232         try {
233             if (latch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) return true;
234             Log.e(TAG, "latch timed out");
235         } catch (InterruptedException e) {
236             /* ignore */
237             Log.e(TAG, "Interrupted", e);
238         }
239         return false;
240     }
241 
await(Condition condition)242     public static boolean await(Condition condition) {
243         try {
244             if (condition.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) return true;
245             Log.e(TAG, "condition timed out");
246         } catch (InterruptedException e) {
247             /* ignore */
248             Log.e(TAG, "Interrupted", e);
249         }
250         return false;
251     }
252 
getParcelableSize(Parcelable parcelable)253     public static int getParcelableSize(Parcelable parcelable) {
254         final Parcel p = Parcel.obtain();
255         parcelable.writeToParcel(p, 0);
256         p.setDataPosition(0);
257         final int size = p.dataSize();
258         p.recycle();
259         return size;
260     }
261 
bitCount(long value)262     public static int bitCount(long value) {
263         int bits = 0;
264         while (value > 0) {
265             bits++;
266             value = value >> 1;
267         }
268         return bits;
269     }
270 }
271