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