blob: 12aed251904f22b778f2189a38157ec25564ddb9 [file] [log] [blame]
Dianne Hackborn91097de2014-04-04 18:02:06 -07001/**
2 * Copyright (C) 2014 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
17package android.service.voice;
18
James Cook6cf39752015-06-04 14:18:43 -070019import android.annotation.Nullable;
Amith Yamasani0af6fa72016-01-17 15:36:19 -080020import android.app.Activity;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070021import android.app.Dialog;
22import android.app.Instrumentation;
Dianne Hackborn3d07c942015-03-13 18:02:54 -070023import android.app.VoiceInteractor;
Dianne Hackborn69c6adc2015-06-02 10:52:59 -070024import android.app.assist.AssistContent;
25import android.app.assist.AssistStructure;
Dianne Hackborn1e383822015-04-10 14:02:33 -070026import android.content.ComponentCallbacks2;
Dianne Hackborn91097de2014-04-04 18:02:06 -070027import android.content.Context;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070028import android.content.Intent;
Dianne Hackborn1e383822015-04-10 14:02:33 -070029import android.content.res.Configuration;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070030import android.content.res.TypedArray;
Dianne Hackborn27eac1d2015-03-16 17:15:53 -070031import android.graphics.Bitmap;
Dianne Hackborne30e02f2014-05-27 18:24:45 -070032import android.graphics.Rect;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070033import android.graphics.Region;
34import android.inputmethodservice.SoftInputWindow;
Dianne Hackborn91097de2014-04-04 18:02:06 -070035import android.os.Binder;
36import android.os.Bundle;
37import android.os.Handler;
38import android.os.IBinder;
39import android.os.Message;
40import android.os.RemoteException;
Dianne Hackborn57dd7372015-07-27 18:11:14 -070041import android.os.UserHandle;
Dianne Hackborn91097de2014-04-04 18:02:06 -070042import android.util.ArrayMap;
Dianne Hackborn57dd7372015-07-27 18:11:14 -070043import android.util.DebugUtils;
Dianne Hackborn91097de2014-04-04 18:02:06 -070044import android.util.Log;
Dianne Hackborne30e02f2014-05-27 18:24:45 -070045import android.view.Gravity;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070046import android.view.KeyEvent;
47import android.view.LayoutInflater;
48import android.view.View;
49import android.view.ViewGroup;
50import android.view.ViewTreeObserver;
51import android.view.WindowManager;
52import android.widget.FrameLayout;
Amith Yamasani0af6fa72016-01-17 15:36:19 -080053
Dianne Hackbornc03c9162014-05-02 10:45:59 -070054import com.android.internal.app.IVoiceInteractionManagerService;
Jorim Jaggi225d3b52015-04-01 11:18:57 -070055import com.android.internal.app.IVoiceInteractionSessionShowCallback;
Dianne Hackborn91097de2014-04-04 18:02:06 -070056import com.android.internal.app.IVoiceInteractor;
57import com.android.internal.app.IVoiceInteractorCallback;
58import com.android.internal.app.IVoiceInteractorRequest;
59import com.android.internal.os.HandlerCaller;
60import com.android.internal.os.SomeArgs;
61
Dianne Hackborn57dd7372015-07-27 18:11:14 -070062import java.io.FileDescriptor;
63import java.io.PrintWriter;
Dianne Hackborna2c076d2014-05-30 16:42:57 -070064import java.lang.ref.WeakReference;
65
Dianne Hackbornc03c9162014-05-02 10:45:59 -070066import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Dianne Hackbornc03c9162014-05-02 10:45:59 -070067
Dianne Hackborna2c076d2014-05-30 16:42:57 -070068/**
Dianne Hackborn4e106ce2015-01-14 15:15:34 -080069 * An active voice interaction session, providing a facility for the implementation
Dianne Hackbornffeecb12015-02-25 11:08:11 -080070 * to interact with the user in the voice interaction layer. The user interface is
71 * initially shown by default, and can be created be overriding {@link #onCreateContentView()}
72 * in which the UI can be built.
Dianne Hackborn4e106ce2015-01-14 15:15:34 -080073 *
74 * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
75 * when done. It can also initiate voice interactions with applications by calling
76 * {@link #startVoiceActivity}</p>.
Dianne Hackborna2c076d2014-05-30 16:42:57 -070077 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -070078public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 {
Dianne Hackborn91097de2014-04-04 18:02:06 -070079 static final String TAG = "VoiceInteractionSession";
Amith Yamasanie8222e52016-04-08 15:28:47 -070080 static final boolean DEBUG = false;
Dianne Hackborn91097de2014-04-04 18:02:06 -070081
Dianne Hackborn2ee5c362015-05-29 17:58:53 -070082 /**
83 * Flag received in {@link #onShow}: originator requested that the session be started with
84 * assist data from the currently focused activity.
85 */
86 public static final int SHOW_WITH_ASSIST = 1<<0;
87
88 /**
Dianne Hackborn2ee5c362015-05-29 17:58:53 -070089 * Flag received in {@link #onShow}: originator requested that the session be started with
90 * a screen shot of the currently focused activity.
91 */
92 public static final int SHOW_WITH_SCREENSHOT = 1<<1;
93
94 /**
95 * Flag for use with {@link #onShow}: indicates that the session has been started from the
96 * system assist gesture.
97 */
98 public static final int SHOW_SOURCE_ASSIST_GESTURE = 1<<2;
99
Dianne Hackborn17f69352015-07-17 18:04:14 -0700100 /**
101 * Flag for use with {@link #onShow}: indicates that the application itself has invoked
102 * the assistant.
103 */
104 public static final int SHOW_SOURCE_APPLICATION = 1<<3;
105
Amith Yamasani0af6fa72016-01-17 15:36:19 -0800106 /**
107 * Flag for use with {@link #onShow}: indicates that an Activity has invoked the voice
108 * interaction service for a local interaction using
109 * {@link Activity#startLocalVoiceInteraction(Bundle)}.
110 */
111 public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
112
Amith Yamasanie8222e52016-04-08 15:28:47 -0700113 // Keys for Bundle values
114 /** @hide */
115 public static final String KEY_DATA = "data";
116 /** @hide */
117 public static final String KEY_STRUCTURE = "structure";
118 /** @hide */
119 public static final String KEY_CONTENT = "content";
120 /** @hide */
121 public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
Felipe Leme29a5b0d2016-10-25 14:57:11 -0700122 /** @hide */
123 public static final String KEY_AUTO_FILL_CALLBACK = "autoFillCallback";
Amith Yamasanie8222e52016-04-08 15:28:47 -0700124
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700125 final Context mContext;
126 final HandlerCaller mHandlerCaller;
127
128 final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
129
130 IVoiceInteractionManagerService mSystemService;
131 IBinder mToken;
132
133 int mTheme = 0;
134 LayoutInflater mInflater;
135 TypedArray mThemeAttrs;
136 View mRootView;
137 FrameLayout mContentFrame;
138 SoftInputWindow mWindow;
139
140 boolean mInitialized;
141 boolean mWindowAdded;
142 boolean mWindowVisible;
143 boolean mWindowWasVisible;
144 boolean mInShowWindow;
145
146 final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
147
148 final Insets mTmpInsets = new Insets();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700149
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700150 final WeakReference<VoiceInteractionSession> mWeakRef
151 = new WeakReference<VoiceInteractionSession>(this);
152
Dianne Hackborn91097de2014-04-04 18:02:06 -0700153 final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
154 @Override
155 public IVoiceInteractorRequest startConfirmation(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700156 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700157 ConfirmationRequest request = new ConfirmationRequest(callingPackage,
158 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
159 prompt, extras);
160 addRequest(request);
161 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_CONFIRMATION,
162 request));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700163 return request.mInterface;
164 }
165
166 @Override
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700167 public IVoiceInteractorRequest startPickOption(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700168 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt,
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700169 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700170 PickOptionRequest request = new PickOptionRequest(callingPackage,
171 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
172 prompt, options, extras);
173 addRequest(request);
174 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_PICK_OPTION,
175 request));
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700176 return request.mInterface;
177 }
178
179 @Override
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700180 public IVoiceInteractorRequest startCompleteVoice(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700181 IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700182 CompleteVoiceRequest request = new CompleteVoiceRequest(callingPackage,
183 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
184 message, extras);
185 addRequest(request);
186 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMPLETE_VOICE,
187 request));
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700188 return request.mInterface;
189 }
190
191 @Override
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700192 public IVoiceInteractorRequest startAbortVoice(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700193 IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700194 AbortVoiceRequest request = new AbortVoiceRequest(callingPackage,
195 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
196 message, extras);
197 addRequest(request);
198 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_ABORT_VOICE,
199 request));
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700200 return request.mInterface;
201 }
202
203 @Override
Dianne Hackborn91097de2014-04-04 18:02:06 -0700204 public IVoiceInteractorRequest startCommand(String callingPackage,
205 IVoiceInteractorCallback callback, String command, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700206 CommandRequest request = new CommandRequest(callingPackage,
207 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
208 command, extras);
Dianne Hackborn593334a2015-06-30 14:38:17 -0700209 addRequest(request);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700210 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMMAND,
211 request));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700212 return request.mInterface;
213 }
214
215 @Override
216 public boolean[] supportsCommands(String callingPackage, String[] commands) {
217 Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700218 0, commands, null);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700219 SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
220 if (args != null) {
221 boolean[] res = (boolean[])args.arg1;
222 args.recycle();
223 return res;
224 }
225 return new boolean[commands.length];
226 }
227 };
228
229 final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700230 @Override
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700231 public void show(Bundle sessionArgs, int flags,
232 IVoiceInteractionSessionShowCallback showCallback) {
233 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_SHOW,
234 flags, sessionArgs, showCallback));
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800235 }
236
237 @Override
238 public void hide() {
239 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
240 }
241
242 @Override
Dianne Hackborn782d4982015-07-08 17:36:37 -0700243 public void handleAssist(final Bundle data, final AssistStructure structure,
Amith Yamasanie8222e52016-04-08 15:28:47 -0700244 final AssistContent content, final int index, final int count) {
Dianne Hackborn5688b032015-04-02 18:25:35 -0700245 // We want to pre-warm the AssistStructure before handing it off to the main
Dianne Hackborn782d4982015-07-08 17:36:37 -0700246 // thread. We also want to do this on a separate thread, so that if the app
247 // is for some reason slow (due to slow filling in of async children in the
248 // structure), we don't block other incoming IPCs (such as the screenshot) to
249 // us (since we are a oneway interface, they get serialized). (Okay?)
250 Thread retriever = new Thread("AssistStructure retriever") {
251 @Override
252 public void run() {
253 Throwable failure = null;
254 if (structure != null) {
255 try {
256 structure.ensureData();
257 } catch (Throwable e) {
258 Log.w(TAG, "Failure retrieving AssistStructure", e);
259 failure = e;
260 }
261 }
Amith Yamasanie8222e52016-04-08 15:28:47 -0700262 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_HANDLE_ASSIST,
263 data, failure == null ? structure : null, failure, content,
264 index, count));
Dianne Hackborn782d4982015-07-08 17:36:37 -0700265 }
266 };
267 retriever.start();
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800268 }
269
270 @Override
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700271 public void handleScreenshot(Bitmap screenshot) {
272 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_SCREENSHOT,
273 screenshot));
274 }
275
276 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700277 public void taskStarted(Intent intent, int taskId) {
278 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
279 taskId, intent));
280 }
281
282 @Override
283 public void taskFinished(Intent intent, int taskId) {
284 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
285 taskId, intent));
286 }
287
288 @Override
289 public void closeSystemDialogs() {
290 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
291 }
292
293 @Override
Jorim Jaggi19695d92015-07-20 15:51:40 -0700294 public void onLockscreenShown() {
295 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_ON_LOCKSCREEN_SHOWN));
296 }
297
298 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700299 public void destroy() {
300 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
301 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700302 };
303
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700304 /**
305 * Base class representing a request from a voice-driver app to perform a particular
306 * voice operation with the user. See related subclasses for the types of requests
307 * that are possible.
308 */
Dianne Hackborn593334a2015-06-30 14:38:17 -0700309 public static class Request {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700310 final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
311 @Override
312 public void cancel() throws RemoteException {
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700313 VoiceInteractionSession session = mSession.get();
314 if (session != null) {
315 session.mHandlerCaller.sendMessage(
316 session.mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
317 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700318 }
319 };
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700320 final String mCallingPackage;
321 final int mCallingUid;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700322 final IVoiceInteractorCallback mCallback;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700323 final WeakReference<VoiceInteractionSession> mSession;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700324 final Bundle mExtras;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700325
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700326 Request(String packageName, int uid, IVoiceInteractorCallback callback,
327 VoiceInteractionSession session, Bundle extras) {
328 mCallingPackage = packageName;
329 mCallingUid = uid;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700330 mCallback = callback;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700331 mSession = session.mWeakRef;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700332 mExtras = extras;
333 }
334
335 /**
336 * Return the uid of the application that initiated the request.
337 */
338 public int getCallingUid() {
339 return mCallingUid;
340 }
341
342 /**
343 * Return the package name of the application that initiated the request.
344 */
345 public String getCallingPackage() {
346 return mCallingPackage;
347 }
348
349 /**
350 * Return any additional extra information that was supplied as part of the request.
351 */
352 public Bundle getExtras() {
353 return mExtras;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700354 }
355
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700356 /**
357 * Check whether this request is currently active. A request becomes inactive after
358 * calling {@link #cancel} or a final result method that completes the request. After
359 * this point, further interactions with the request will result in
360 * {@link java.lang.IllegalStateException} errors; you should not catch these errors,
361 * but can use this method if you need to determine the state of the request. Returns
362 * true if the request is still active.
363 */
364 public boolean isActive() {
365 VoiceInteractionSession session = mSession.get();
366 if (session == null) {
367 return false;
368 }
369 return session.isRequestActive(mInterface.asBinder());
370 }
371
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700372 void finishRequest() {
373 VoiceInteractionSession session = mSession.get();
374 if (session == null) {
375 throw new IllegalStateException("VoiceInteractionSession has been destroyed");
376 }
377 Request req = session.removeRequest(mInterface.asBinder());
378 if (req == null) {
379 throw new IllegalStateException("Request not active: " + this);
380 } else if (req != this) {
381 throw new IllegalStateException("Current active request " + req
382 + " not same as calling request " + this);
383 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700384 }
385
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700386 /**
Dianne Hackborn593334a2015-06-30 14:38:17 -0700387 * Ask the app to cancel this current request.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700388 * This also finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700389 */
390 public void cancel() {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700391 try {
392 if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700393 finishRequest();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700394 mCallback.deliverCancel(mInterface);
395 } catch (RemoteException e) {
396 }
397 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700398
399 @Override
400 public String toString() {
401 StringBuilder sb = new StringBuilder(128);
402 DebugUtils.buildShortClassTag(this, sb);
403 sb.append(" ");
404 sb.append(mInterface.asBinder());
405 sb.append(" pkg=");
406 sb.append(mCallingPackage);
407 sb.append(" uid=");
408 UserHandle.formatUid(sb, mCallingUid);
409 sb.append('}');
410 return sb.toString();
411 }
412
413 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
414 writer.print(prefix); writer.print("mInterface=");
415 writer.println(mInterface.asBinder());
416 writer.print(prefix); writer.print("mCallingPackage="); writer.print(mCallingPackage);
417 writer.print(" mCallingUid="); UserHandle.formatUid(writer, mCallingUid);
418 writer.println();
419 writer.print(prefix); writer.print("mCallback=");
420 writer.println(mCallback.asBinder());
421 if (mExtras != null) {
422 writer.print(prefix); writer.print("mExtras=");
423 writer.println(mExtras);
424 }
425 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700426 }
427
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700428 /**
429 * A request for confirmation from the user of an operation, as per
430 * {@link android.app.VoiceInteractor.ConfirmationRequest
431 * VoiceInteractor.ConfirmationRequest}.
432 */
433 public static final class ConfirmationRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700434 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700435
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700436 ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700437 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700438 super(packageName, uid, callback, session, extras);
439 mPrompt = prompt;
440 }
441
442 /**
443 * Return the prompt informing the user of what will happen, as per
444 * {@link android.app.VoiceInteractor.ConfirmationRequest
445 * VoiceInteractor.ConfirmationRequest}.
446 */
James Cook6cf39752015-06-04 14:18:43 -0700447 @Nullable
448 public VoiceInteractor.Prompt getVoicePrompt() {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700449 return mPrompt;
450 }
451
452 /**
James Cook6cf39752015-06-04 14:18:43 -0700453 * Return the prompt informing the user of what will happen, as per
454 * {@link android.app.VoiceInteractor.ConfirmationRequest
455 * VoiceInteractor.ConfirmationRequest}.
456 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
457 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700458 @Deprecated
James Cook6cf39752015-06-04 14:18:43 -0700459 @Nullable
460 public CharSequence getPrompt() {
461 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
462 }
463
464 /**
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700465 * Report that the voice interactor has confirmed the operation with the user, resulting
466 * in a call to
467 * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult
468 * VoiceInteractor.ConfirmationRequest.onConfirmationResult}.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700469 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700470 */
471 public void sendConfirmationResult(boolean confirmed, Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700472 try {
473 if (DEBUG) Log.d(TAG, "sendConfirmationResult: req=" + mInterface
474 + " confirmed=" + confirmed + " result=" + result);
475 finishRequest();
476 mCallback.deliverConfirmationResult(mInterface, confirmed, result);
477 } catch (RemoteException e) {
478 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700479 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700480
481 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
482 super.dump(prefix, fd, writer, args);
483 writer.print(prefix); writer.print("mPrompt=");
484 writer.println(mPrompt);
485 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700486 }
487
488 /**
489 * A request for the user to pick from a set of option, as per
490 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
491 */
492 public static final class PickOptionRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700493 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700494 final VoiceInteractor.PickOptionRequest.Option[] mOptions;
495
496 PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700497 VoiceInteractionSession session, VoiceInteractor.Prompt prompt,
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700498 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
499 super(packageName, uid, callback, session, extras);
500 mPrompt = prompt;
501 mOptions = options;
502 }
503
504 /**
505 * Return the prompt informing the user of what they are picking, as per
506 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
507 */
James Cook6cf39752015-06-04 14:18:43 -0700508 @Nullable
509 public VoiceInteractor.Prompt getVoicePrompt() {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700510 return mPrompt;
511 }
512
513 /**
James Cook6cf39752015-06-04 14:18:43 -0700514 * Return the prompt informing the user of what they are picking, as per
515 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
516 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
517 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700518 @Deprecated
James Cook6cf39752015-06-04 14:18:43 -0700519 @Nullable
520 public CharSequence getPrompt() {
521 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
522 }
523
524 /**
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700525 * Return the set of options the user is picking from, as per
526 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
527 */
528 public VoiceInteractor.PickOptionRequest.Option[] getOptions() {
529 return mOptions;
530 }
531
Dianne Hackborn593334a2015-06-30 14:38:17 -0700532 void sendPickOptionResult(boolean finished,
533 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
534 try {
535 if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface
536 + " finished=" + finished + " selections=" + selections
537 + " result=" + result);
538 if (finished) {
539 finishRequest();
540 }
541 mCallback.deliverPickOptionResult(mInterface, finished, selections, result);
542 } catch (RemoteException e) {
543 }
544 }
545
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700546 /**
547 * Report an intermediate option selection from the request, without completing it (the
548 * request is still active and the app is waiting for the final option selection),
549 * resulting in a call to
550 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
551 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
552 */
553 public void sendIntermediatePickOptionResult(
554 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
555 sendPickOptionResult(false, selections, result);
556 }
557
558 /**
559 * Report the final option selection for the request, completing the request
560 * and resulting in a call to
561 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
562 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700563 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700564 */
565 public void sendPickOptionResult(
566 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
567 sendPickOptionResult(true, selections, result);
568 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700569
570 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
571 super.dump(prefix, fd, writer, args);
572 writer.print(prefix); writer.print("mPrompt=");
573 writer.println(mPrompt);
574 if (mOptions != null) {
575 writer.print(prefix); writer.println("Options:");
576 for (int i=0; i<mOptions.length; i++) {
577 VoiceInteractor.PickOptionRequest.Option op = mOptions[i];
578 writer.print(prefix); writer.print(" #"); writer.print(i); writer.println(":");
579 writer.print(prefix); writer.print(" mLabel=");
580 writer.println(op.getLabel());
581 writer.print(prefix); writer.print(" mIndex=");
582 writer.println(op.getIndex());
583 if (op.countSynonyms() > 0) {
584 writer.print(prefix); writer.println(" Synonyms:");
585 for (int j=0; j<op.countSynonyms(); j++) {
586 writer.print(prefix); writer.print(" #"); writer.print(j);
587 writer.print(": "); writer.println(op.getSynonymAt(j));
588 }
589 }
590 if (op.getExtras() != null) {
591 writer.print(prefix); writer.print(" mExtras=");
592 writer.println(op.getExtras());
593 }
594 }
595 }
596 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700597 }
598
599 /**
600 * A request to simply inform the user that the voice operation has completed, as per
601 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
602 * VoiceInteractor.CompleteVoiceRequest}.
603 */
604 public static final class CompleteVoiceRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700605 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700606
607 CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700608 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700609 super(packageName, uid, callback, session, extras);
James Cook6cf39752015-06-04 14:18:43 -0700610 mPrompt = prompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700611 }
612
613 /**
614 * Return the message informing the user of the completion, as per
615 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
616 * VoiceInteractor.CompleteVoiceRequest}.
617 */
James Cook6cf39752015-06-04 14:18:43 -0700618 @Nullable
619 public VoiceInteractor.Prompt getVoicePrompt() {
620 return mPrompt;
621 }
622
623 /**
624 * Return the message informing the user of the completion, as per
625 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
626 * VoiceInteractor.CompleteVoiceRequest}.
627 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
628 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700629 @Deprecated
James Cook6cf39752015-06-04 14:18:43 -0700630 @Nullable
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700631 public CharSequence getMessage() {
James Cook6cf39752015-06-04 14:18:43 -0700632 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700633 }
634
635 /**
636 * Report that the voice interactor has finished completing the voice operation, resulting
637 * in a call to
638 * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult
639 * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700640 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700641 */
642 public void sendCompleteResult(Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700643 try {
644 if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface
645 + " result=" + result);
646 finishRequest();
647 mCallback.deliverCompleteVoiceResult(mInterface, result);
648 } catch (RemoteException e) {
649 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700650 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700651
652 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
653 super.dump(prefix, fd, writer, args);
654 writer.print(prefix); writer.print("mPrompt=");
655 writer.println(mPrompt);
656 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700657 }
658
659 /**
660 * A request to report that the current user interaction can not be completed with voice, as per
661 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
662 */
663 public static final class AbortVoiceRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700664 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700665
666 AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700667 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700668 super(packageName, uid, callback, session, extras);
James Cook6cf39752015-06-04 14:18:43 -0700669 mPrompt = prompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700670 }
671
672 /**
673 * Return the message informing the user of the problem, as per
674 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
675 */
James Cook6cf39752015-06-04 14:18:43 -0700676 @Nullable
677 public VoiceInteractor.Prompt getVoicePrompt() {
678 return mPrompt;
679 }
680
681 /**
682 * Return the message informing the user of the problem, as per
683 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
684 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
685 */
Aurimas Liutikas514c5ef2016-05-24 15:22:55 -0700686 @Deprecated
James Cook6cf39752015-06-04 14:18:43 -0700687 @Nullable
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700688 public CharSequence getMessage() {
James Cook6cf39752015-06-04 14:18:43 -0700689 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700690 }
691
692 /**
693 * Report that the voice interactor has finished aborting the voice operation, resulting
694 * in a call to
695 * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700696 * VoiceInteractor.AbortVoiceRequest.onAbortResult}. This finishes the request (it
697 * is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700698 */
699 public void sendAbortResult(Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700700 try {
701 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
702 + " result=" + result);
703 finishRequest();
704 mCallback.deliverAbortVoiceResult(mInterface, result);
705 } catch (RemoteException e) {
706 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700707 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700708
709 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
710 super.dump(prefix, fd, writer, args);
711 writer.print(prefix); writer.print("mPrompt=");
712 writer.println(mPrompt);
713 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700714 }
715
716 /**
717 * A generic vendor-specific request, as per
718 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
719 */
720 public static final class CommandRequest extends Request {
721 final String mCommand;
722
723 CommandRequest(String packageName, int uid, IVoiceInteractorCallback callback,
724 VoiceInteractionSession session, String command, Bundle extras) {
725 super(packageName, uid, callback, session, extras);
726 mCommand = command;
727 }
728
729 /**
730 * Return the command that is being executed, as per
731 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
732 */
733 public String getCommand() {
734 return mCommand;
735 }
736
Dianne Hackborn593334a2015-06-30 14:38:17 -0700737 void sendCommandResult(boolean finished, Bundle result) {
738 try {
739 if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
740 + " result=" + result);
741 if (finished) {
742 finishRequest();
743 }
744 mCallback.deliverCommandResult(mInterface, finished, result);
745 } catch (RemoteException e) {
746 }
747 }
748
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700749 /**
750 * Report an intermediate result of the request, without completing it (the request
751 * is still active and the app is waiting for the final result), resulting in a call to
752 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
753 * VoiceInteractor.CommandRequest.onCommandResult} with false for isCompleted.
754 */
755 public void sendIntermediateResult(Bundle result) {
756 sendCommandResult(false, result);
757 }
758
759 /**
760 * Report the final result of the request, completing the request and resulting in a call to
761 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
762 * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700763 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700764 */
765 public void sendResult(Bundle result) {
766 sendCommandResult(true, result);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700767 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700768
769 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
770 super.dump(prefix, fd, writer, args);
771 writer.print(prefix); writer.print("mCommand=");
772 writer.println(mCommand);
773 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700774 }
775
776 static final int MSG_START_CONFIRMATION = 1;
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700777 static final int MSG_START_PICK_OPTION = 2;
778 static final int MSG_START_COMPLETE_VOICE = 3;
779 static final int MSG_START_ABORT_VOICE = 4;
780 static final int MSG_START_COMMAND = 5;
781 static final int MSG_SUPPORTS_COMMANDS = 6;
782 static final int MSG_CANCEL = 7;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700783
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700784 static final int MSG_TASK_STARTED = 100;
785 static final int MSG_TASK_FINISHED = 101;
786 static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
787 static final int MSG_DESTROY = 103;
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800788 static final int MSG_HANDLE_ASSIST = 104;
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700789 static final int MSG_HANDLE_SCREENSHOT = 105;
790 static final int MSG_SHOW = 106;
791 static final int MSG_HIDE = 107;
Jorim Jaggi19695d92015-07-20 15:51:40 -0700792 static final int MSG_ON_LOCKSCREEN_SHOWN = 108;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700793
794 class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700795 @Override
796 public void executeMessage(Message msg) {
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700797 SomeArgs args = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700798 switch (msg.what) {
799 case MSG_START_CONFIRMATION:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700800 if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
801 onRequestConfirmation((ConfirmationRequest) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700802 break;
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700803 case MSG_START_PICK_OPTION:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700804 if (DEBUG) Log.d(TAG, "onPickOption: req=" + msg.obj);
805 onRequestPickOption((PickOptionRequest) msg.obj);
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700806 break;
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700807 case MSG_START_COMPLETE_VOICE:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700808 if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + msg.obj);
809 onRequestCompleteVoice((CompleteVoiceRequest) msg.obj);
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700810 break;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700811 case MSG_START_ABORT_VOICE:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700812 if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + msg.obj);
813 onRequestAbortVoice((AbortVoiceRequest) msg.obj);
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700814 break;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700815 case MSG_START_COMMAND:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700816 if (DEBUG) Log.d(TAG, "onCommand: req=" + msg.obj);
817 onRequestCommand((CommandRequest) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700818 break;
819 case MSG_SUPPORTS_COMMANDS:
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700820 args = (SomeArgs)msg.obj;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700821 if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
822 args.arg1 = onGetSupportedCommands((String[]) args.arg1);
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700823 args.complete();
824 args = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700825 break;
826 case MSG_CANCEL:
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800827 if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700828 onCancelRequest((Request) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700829 break;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700830 case MSG_TASK_STARTED:
831 if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
832 + " taskId=" + msg.arg1);
833 onTaskStarted((Intent) msg.obj, msg.arg1);
834 break;
835 case MSG_TASK_FINISHED:
836 if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
837 + " taskId=" + msg.arg1);
838 onTaskFinished((Intent) msg.obj, msg.arg1);
839 break;
840 case MSG_CLOSE_SYSTEM_DIALOGS:
841 if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
842 onCloseSystemDialogs();
843 break;
844 case MSG_DESTROY:
845 if (DEBUG) Log.d(TAG, "doDestroy");
846 doDestroy();
847 break;
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800848 case MSG_HANDLE_ASSIST:
Dianne Hackborn09d57fe2015-05-27 18:05:52 -0700849 args = (SomeArgs)msg.obj;
850 if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
Amith Yamasanie8222e52016-04-08 15:28:47 -0700851 + " structure=" + args.arg2 + " content=" + args.arg3
852 + " activityIndex=" + args.argi5 + " activityCount=" + args.argi6);
853 if (args.argi5 == 0) {
854 doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
855 (Throwable) args.arg3, (AssistContent) args.arg4);
856 } else {
857 doOnHandleAssistSecondary((Bundle) args.arg1, (AssistStructure) args.arg2,
858 (Throwable) args.arg3, (AssistContent) args.arg4,
859 args.argi5, args.argi6);
860 }
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800861 break;
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700862 case MSG_HANDLE_SCREENSHOT:
863 if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
864 onHandleScreenshot((Bitmap) msg.obj);
865 break;
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800866 case MSG_SHOW:
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700867 args = (SomeArgs)msg.obj;
868 if (DEBUG) Log.d(TAG, "doShow: args=" + args.arg1
869 + " flags=" + msg.arg1
870 + " showCallback=" + args.arg2);
871 doShow((Bundle) args.arg1, msg.arg1,
872 (IVoiceInteractionSessionShowCallback) args.arg2);
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800873 break;
874 case MSG_HIDE:
875 if (DEBUG) Log.d(TAG, "doHide");
876 doHide();
877 break;
Jorim Jaggi19695d92015-07-20 15:51:40 -0700878 case MSG_ON_LOCKSCREEN_SHOWN:
879 if (DEBUG) Log.d(TAG, "onLockscreenShown");
880 onLockscreenShown();
881 break;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700882 }
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700883 if (args != null) {
884 args.recycle();
885 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700886 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700887
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700888 @Override
889 public void onBackPressed() {
890 VoiceInteractionSession.this.onBackPressed();
891 }
892 }
893
894 final MyCallbacks mCallbacks = new MyCallbacks();
895
896 /**
897 * Information about where interesting parts of the input method UI appear.
898 */
899 public static final class Insets {
900 /**
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700901 * This is the part of the UI that is the main content. It is
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700902 * used to determine the basic space needed, to resize/pan the
903 * application behind. It is assumed that this inset does not
904 * change very much, since any change will cause a full resize/pan
905 * of the application behind. This value is relative to the top edge
906 * of the input method window.
907 */
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700908 public final Rect contentInsets = new Rect();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700909
910 /**
911 * This is the region of the UI that is touchable. It is used when
912 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
913 * The region should be specified relative to the origin of the window frame.
914 */
915 public final Region touchableRegion = new Region();
916
917 /**
918 * Option for {@link #touchableInsets}: the entire window frame
919 * can be touched.
920 */
921 public static final int TOUCHABLE_INSETS_FRAME
922 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
923
924 /**
925 * Option for {@link #touchableInsets}: the area inside of
926 * the content insets can be touched.
927 */
928 public static final int TOUCHABLE_INSETS_CONTENT
929 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
930
931 /**
932 * Option for {@link #touchableInsets}: the region specified by
933 * {@link #touchableRegion} can be touched.
934 */
935 public static final int TOUCHABLE_INSETS_REGION
936 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
937
938 /**
939 * Determine which area of the window is touchable by the user. May
940 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
941 * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
942 */
943 public int touchableInsets;
944 }
945
946 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
947 new ViewTreeObserver.OnComputeInternalInsetsListener() {
948 public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
949 onComputeInsets(mTmpInsets);
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700950 info.contentInsets.set(mTmpInsets.contentInsets);
951 info.visibleInsets.set(mTmpInsets.contentInsets);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700952 info.touchableRegion.set(mTmpInsets.touchableRegion);
953 info.setTouchableInsets(mTmpInsets.touchableInsets);
954 }
955 };
Dianne Hackborn91097de2014-04-04 18:02:06 -0700956
957 public VoiceInteractionSession(Context context) {
958 this(context, new Handler());
959 }
960
961 public VoiceInteractionSession(Context context, Handler handler) {
962 mContext = context;
963 mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700964 mCallbacks, true);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700965 }
966
Dianne Hackbornd59a5d52015-04-04 14:52:14 -0700967 public Context getContext() {
968 return mContext;
969 }
970
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700971 void addRequest(Request req) {
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700972 synchronized (this) {
973 mActiveRequests.put(req.mInterface.asBinder(), req);
974 }
975 }
976
977 boolean isRequestActive(IBinder reqInterface) {
978 synchronized (this) {
979 return mActiveRequests.containsKey(reqInterface);
980 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700981 }
982
983 Request removeRequest(IBinder reqInterface) {
984 synchronized (this) {
Andreas Gampe8ef92bd2015-03-17 21:22:49 -0700985 return mActiveRequests.remove(reqInterface);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700986 }
987 }
988
Dianne Hackborn593334a2015-06-30 14:38:17 -0700989 void doCreate(IVoiceInteractionManagerService service, IBinder token) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700990 mSystemService = service;
991 mToken = token;
Dianne Hackborn593334a2015-06-30 14:38:17 -0700992 onCreate();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700993 }
994
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700995 void doShow(Bundle args, int flags, final IVoiceInteractionSessionShowCallback showCallback) {
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800996 if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
997 + " mWindowVisible=" + mWindowVisible);
998
999 if (mInShowWindow) {
1000 Log.w(TAG, "Re-entrance in to showWindow");
1001 return;
1002 }
1003
1004 try {
1005 mInShowWindow = true;
1006 if (!mWindowVisible) {
1007 if (!mWindowAdded) {
1008 mWindowAdded = true;
1009 View v = onCreateContentView();
1010 if (v != null) {
1011 setContentView(v);
1012 }
1013 }
1014 }
1015 onShow(args, flags);
1016 if (!mWindowVisible) {
1017 mWindowVisible = true;
1018 mWindow.show();
1019 }
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001020 if (showCallback != null) {
1021 mRootView.invalidate();
1022 mRootView.getViewTreeObserver().addOnPreDrawListener(
1023 new ViewTreeObserver.OnPreDrawListener() {
1024 @Override
1025 public boolean onPreDraw() {
1026 mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
1027 try {
1028 showCallback.onShown();
1029 } catch (RemoteException e) {
1030 Log.w(TAG, "Error calling onShown", e);
1031 }
1032 return true;
1033 }
1034 });
1035 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001036 } finally {
1037 mWindowWasVisible = true;
1038 mInShowWindow = false;
1039 }
1040 }
1041
1042 void doHide() {
1043 if (mWindowVisible) {
1044 mWindow.hide();
1045 mWindowVisible = false;
1046 onHide();
1047 }
1048 }
1049
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001050 void doDestroy() {
Dianne Hackborn9a35d782014-08-07 12:34:37 -07001051 onDestroy();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001052 if (mInitialized) {
1053 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
1054 mInsetsComputer);
1055 if (mWindowAdded) {
1056 mWindow.dismiss();
1057 mWindowAdded = false;
1058 }
1059 mInitialized = false;
1060 }
1061 }
1062
1063 void initViews() {
1064 mInitialized = true;
1065
1066 mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
1067 mRootView = mInflater.inflate(
1068 com.android.internal.R.layout.voice_interaction_session, null);
1069 mRootView.setSystemUiVisibility(
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001070 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
1071 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001072 mWindow.setContentView(mRootView);
1073 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
1074
1075 mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
1076 }
1077
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001078 /**
Dianne Hackborn1de11862015-07-15 14:20:51 -07001079 * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
1080 * VoiceInteractionService.setDisabledShowContext(int)}.
1081 */
1082 public void setDisabledShowContext(int flags) {
1083 try {
1084 mSystemService.setDisabledShowContext(flags);
1085 } catch (RemoteException e) {
1086 }
1087 }
1088
1089 /**
1090 * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
1091 * VoiceInteractionService.getDisabledShowContext}.
1092 */
1093 public int getDisabledShowContext() {
1094 try {
1095 return mSystemService.getDisabledShowContext();
1096 } catch (RemoteException e) {
1097 return 0;
1098 }
1099 }
1100
1101 /**
Dianne Hackborn17f69352015-07-17 18:04:14 -07001102 * Return which show context flags have been disabled by the user through the system
1103 * settings UI, so the session will never get this data. Returned flags are any combination of
1104 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
1105 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
1106 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. Note that this only tells you about
1107 * global user settings, not about restrictions that may be applied contextual based on
1108 * the current application the user is in or other transient states.
1109 */
1110 public int getUserDisabledShowContext() {
1111 try {
1112 return mSystemService.getUserDisabledShowContext();
1113 } catch (RemoteException e) {
1114 return 0;
1115 }
1116 }
1117
1118 /**
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001119 * Show the UI for this session. This asks the system to go through the process of showing
1120 * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling
1121 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1122 * @param args Arbitrary arguments that will be propagated {@link #onShow}.
1123 * @param flags Indicates additional optional behavior that should be performed. May
Dianne Hackborn1de11862015-07-15 14:20:51 -07001124 * be any combination of
1125 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
1126 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
1127 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001128 * to request that the system generate and deliver assist data on the current foreground
1129 * app as part of showing the session UI.
1130 */
1131 public void show(Bundle args, int flags) {
1132 if (mToken == null) {
1133 throw new IllegalStateException("Can't call before onCreate()");
1134 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001135 try {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001136 mSystemService.showSessionFromSession(mToken, args, flags);
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001137 } catch (RemoteException e) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001138 }
1139 }
1140
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001141 /**
1142 * Hide the session's UI, if currently shown. Call this when you are done with your
1143 * user interaction.
1144 */
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001145 public void hide() {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001146 if (mToken == null) {
1147 throw new IllegalStateException("Can't call before onCreate()");
1148 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001149 try {
1150 mSystemService.hideSessionFromSession(mToken);
1151 } catch (RemoteException e) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001152 }
1153 }
1154
1155 /**
1156 * You can call this to customize the theme used by your IME's window.
1157 * This must be set before {@link #onCreate}, so you
1158 * will typically call it in your constructor with the resource ID
1159 * of your custom theme.
1160 */
1161 public void setTheme(int theme) {
1162 if (mWindow != null) {
1163 throw new IllegalStateException("Must be called before onCreate()");
1164 }
1165 mTheme = theme;
1166 }
1167
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001168 /**
1169 * Ask that a new activity be started for voice interaction. This will create a
1170 * new dedicated task in the activity manager for this voice interaction session;
1171 * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
1172 * will be set for you to make it a new task.
1173 *
1174 * <p>The newly started activity will be displayed to the user in a special way, as
1175 * a layer under the voice interaction UI.</p>
1176 *
1177 * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor}
1178 * through which it can perform voice interactions through your session. These requests
1179 * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands},
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001180 * {@link #onRequestConfirmation}, {@link #onRequestPickOption},
1181 * {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1182 * or {@link #onRequestCommand}
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001183 *
1184 * <p>You will receive a call to {@link #onTaskStarted} when the task starts up
1185 * and {@link #onTaskFinished} when the last activity has finished.
1186 *
1187 * @param intent The Intent to start this voice interaction. The given Intent will
1188 * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
1189 * this is part of a voice interaction.
1190 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001191 public void startVoiceActivity(Intent intent) {
1192 if (mToken == null) {
1193 throw new IllegalStateException("Can't call before onCreate()");
1194 }
1195 try {
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001196 intent.migrateExtraStreamToClipData();
Jeff Sharkey344744b2016-01-28 19:03:30 -07001197 intent.prepareToLeaveProcess(mContext);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001198 int res = mSystemService.startVoiceActivity(mToken, intent,
1199 intent.resolveType(mContext.getContentResolver()));
1200 Instrumentation.checkStartActivityResult(res, intent);
1201 } catch (RemoteException e) {
1202 }
1203 }
1204
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001205 /**
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001206 * Set whether this session will keep the device awake while it is running a voice
1207 * activity. By default, the system holds a wake lock for it while in this state,
1208 * so that it can work even if the screen is off. Setting this to false removes that
1209 * wake lock, allowing the CPU to go to sleep. This is typically used if the
1210 * session decides it has been waiting too long for a response from the user and
1211 * doesn't want to let this continue to drain the battery.
1212 *
1213 * <p>Passing false here will release the wake lock, and you can call later with
1214 * true to re-acquire it. It will also be automatically re-acquired for you each
1215 * time you start a new voice activity task -- that is when you call
1216 * {@link #startVoiceActivity}.</p>
1217 */
1218 public void setKeepAwake(boolean keepAwake) {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001219 if (mToken == null) {
1220 throw new IllegalStateException("Can't call before onCreate()");
1221 }
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001222 try {
1223 mSystemService.setKeepAwake(mToken, keepAwake);
1224 } catch (RemoteException e) {
1225 }
1226 }
1227
1228 /**
Dianne Hackborn4e88bcd2015-07-01 13:41:03 -07001229 * Request that all system dialogs (and status bar shade etc) be closed, allowing
1230 * access to the session's UI. This will <em>not</em> cause the lock screen to be
1231 * dismissed.
1232 */
1233 public void closeSystemDialogs() {
1234 if (mToken == null) {
1235 throw new IllegalStateException("Can't call before onCreate()");
1236 }
1237 try {
1238 mSystemService.closeSystemDialogs(mToken);
1239 } catch (RemoteException e) {
1240 }
1241 }
1242
1243 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001244 * Convenience for inflating views.
1245 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001246 public LayoutInflater getLayoutInflater() {
1247 return mInflater;
1248 }
1249
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001250 /**
1251 * Retrieve the window being used to show the session's UI.
1252 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001253 public Dialog getWindow() {
1254 return mWindow;
1255 }
1256
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001257 /**
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001258 * Finish the session. This completely destroys the session -- the next time it is shown,
1259 * an entirely new one will be created. You do not normally call this function; instead,
1260 * use {@link #hide} and allow the system to destroy your session if it needs its RAM.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001261 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001262 public void finish() {
1263 if (mToken == null) {
1264 throw new IllegalStateException("Can't call before onCreate()");
1265 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001266 try {
1267 mSystemService.finish(mToken);
1268 } catch (RemoteException e) {
1269 }
1270 }
1271
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001272 /**
1273 * Initiatize a new session. At this point you don't know exactly what this
1274 * session will be used for; you will find that out in {@link #onShow}.
1275 */
1276 public void onCreate() {
1277 doOnCreate();
1278 }
1279
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001280 private void doOnCreate() {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001281 mTheme = mTheme != 0 ? mTheme
1282 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
1283 mInflater = (LayoutInflater)mContext.getSystemService(
1284 Context.LAYOUT_INFLATER_SERVICE);
1285 mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001286 mCallbacks, this, mDispatcherState,
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001287 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001288 mWindow.getWindow().addFlags(
1289 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
Stefan Kuhne2f280d062015-06-18 07:20:33 -10001290 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
1291 WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001292 initViews();
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001293 mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001294 mWindow.setToken(mToken);
1295 }
1296
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001297 /**
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001298 * Called when the session UI is going to be shown. This is called after
1299 * {@link #onCreateContentView} (if the session's content UI needed to be created) and
1300 * immediately prior to the window being shown. This may be called while the window
1301 * is already shown, if a show request has come in while it is shown, to allow you to
1302 * update the UI to match the new show arguments.
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001303 *
1304 * @param args The arguments that were supplied to
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001305 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1306 * @param showFlags The show flags originally provided to
1307 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001308 */
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001309 public void onShow(Bundle args, int showFlags) {
1310 }
1311
1312 /**
1313 * Called immediately after stopping to show the session UI.
1314 */
1315 public void onHide() {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001316 }
1317
1318 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001319 * Last callback to the session as it is being finished.
1320 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001321 public void onDestroy() {
1322 }
1323
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001324 /**
1325 * Hook in which to create the session's UI.
1326 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001327 public View onCreateContentView() {
1328 return null;
1329 }
1330
1331 public void setContentView(View view) {
1332 mContentFrame.removeAllViews();
1333 mContentFrame.addView(view, new FrameLayout.LayoutParams(
1334 ViewGroup.LayoutParams.MATCH_PARENT,
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001335 ViewGroup.LayoutParams.MATCH_PARENT));
Adam Powell41607d52015-06-17 13:37:06 -07001336 mContentFrame.requestApplyInsets();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001337 }
1338
Dianne Hackborn782d4982015-07-08 17:36:37 -07001339 void doOnHandleAssist(Bundle data, AssistStructure structure, Throwable failure,
1340 AssistContent content) {
1341 if (failure != null) {
1342 onAssistStructureFailure(failure);
1343 }
1344 onHandleAssist(data, structure, content);
1345 }
1346
Amith Yamasanie8222e52016-04-08 15:28:47 -07001347 void doOnHandleAssistSecondary(Bundle data, AssistStructure structure, Throwable failure,
1348 AssistContent content, int index, int count) {
1349 if (failure != null) {
1350 onAssistStructureFailure(failure);
1351 }
1352 onHandleAssistSecondary(data, structure, content, index, count);
1353 }
1354
Dianne Hackborn782d4982015-07-08 17:36:37 -07001355 /**
1356 * Called when there has been a failure transferring the {@link AssistStructure} to
1357 * the assistant. This may happen, for example, if the data is too large and results
1358 * in an out of memory exception, or the client has provided corrupt data. This will
1359 * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied
1360 * there afterwards will be null.
1361 *
1362 * @param failure The failure exception that was thrown when building the
1363 * {@link AssistStructure}.
1364 */
1365 public void onAssistStructureFailure(Throwable failure) {
1366 }
1367
1368 /**
1369 * Called to receive data from the application that the user was currently viewing when
Dianne Hackborn17f69352015-07-17 18:04:14 -07001370 * an assist session is started. If the original show request did not specify
1371 * {@link #SHOW_WITH_ASSIST}, this method will not be called.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001372 *
1373 * @param data Arbitrary data supplied by the app through
1374 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
Dianne Hackborn17f69352015-07-17 18:04:14 -07001375 * May be null if assist data has been disabled by the user or device policy.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001376 * @param structure If available, the structure definition of all windows currently
Dianne Hackborn17f69352015-07-17 18:04:14 -07001377 * displayed by the app. May be null if assist data has been disabled by the user
1378 * or device policy; will be an empty stub if the application has disabled assist
1379 * by marking its window as secure.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001380 * @param content Additional content data supplied by the app through
1381 * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
Dianne Hackborn17f69352015-07-17 18:04:14 -07001382 * May be null if assist data has been disabled by the user or device policy; will
1383 * not be automatically filled in with data from the app if the app has marked its
1384 * window as secure.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001385 */
Dianne Hackborn17f69352015-07-17 18:04:14 -07001386 public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure,
1387 @Nullable AssistContent content) {
Dianne Hackborn09d57fe2015-05-27 18:05:52 -07001388 }
1389
Dianne Hackborn782d4982015-07-08 17:36:37 -07001390 /**
Amith Yamasanie8222e52016-04-08 15:28:47 -07001391 * Called to receive data from other applications that the user was or is interacting with,
1392 * that are currently on the screen in a multi-window display environment, not including the
1393 * currently focused activity. This could be
1394 * a free-form window, a picture-in-picture window, or another window in a split-screen display.
1395 * <p>
1396 * This method is very similar to
1397 * {@link #onHandleAssist} except that it is called
1398 * for additional non-focused activities along with an index and count that indicates
1399 * which additional activity the data is for. {@code index} will be between 1 and
1400 * {@code count}-1 and this method is called once for each additional window, in no particular
1401 * order. The {@code count} indicates how many windows to expect assist data for, including the
1402 * top focused activity, which continues to be returned via {@link #onHandleAssist}.
1403 * <p>
1404 * To be responsive to assist requests, process assist data as soon as it is received,
1405 * without waiting for all queued activities to return assist data.
1406 *
1407 * @param data Arbitrary data supplied by the app through
1408 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
1409 * May be null if assist data has been disabled by the user or device policy.
1410 * @param structure If available, the structure definition of all windows currently
1411 * displayed by the app. May be null if assist data has been disabled by the user
1412 * or device policy; will be an empty stub if the application has disabled assist
1413 * by marking its window as secure.
1414 * @param content Additional content data supplied by the app through
1415 * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
1416 * May be null if assist data has been disabled by the user or device policy; will
1417 * not be automatically filled in with data from the app if the app has marked its
1418 * window as secure.
1419 * @param index the index of the additional activity that this data
1420 * is for.
1421 * @param count the total number of additional activities for which the assist data is being
1422 * returned, including the focused activity that is returned via
1423 * {@link #onHandleAssist}.
1424 */
1425 public void onHandleAssistSecondary(@Nullable Bundle data, @Nullable AssistStructure structure,
1426 @Nullable AssistContent content, int index, int count) {
1427 }
1428
1429 /**
Dianne Hackborn782d4982015-07-08 17:36:37 -07001430 * Called to receive a screenshot of what the user was currently viewing when an assist
Dianne Hackborn17f69352015-07-17 18:04:14 -07001431 * session is started. May be null if screenshots are disabled by the user, policy,
1432 * or application. If the original show request did not specify
1433 * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001434 */
Dianne Hackborn17f69352015-07-17 18:04:14 -07001435 public void onHandleScreenshot(@Nullable Bitmap screenshot) {
Dianne Hackborn27eac1d2015-03-16 17:15:53 -07001436 }
1437
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001438 public boolean onKeyDown(int keyCode, KeyEvent event) {
1439 return false;
1440 }
1441
1442 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1443 return false;
1444 }
1445
1446 public boolean onKeyUp(int keyCode, KeyEvent event) {
1447 return false;
1448 }
1449
1450 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
1451 return false;
1452 }
1453
Dianne Hackbornd59a5d52015-04-04 14:52:14 -07001454 /**
1455 * Called when the user presses the back button while focus is in the session UI. Note
1456 * that this will only happen if the session UI has requested input focus in its window;
1457 * otherwise, the back key will go to whatever window has focus and do whatever behavior
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001458 * it normally has there. The default implementation simply calls {@link #hide}.
Dianne Hackbornd59a5d52015-04-04 14:52:14 -07001459 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001460 public void onBackPressed() {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001461 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001462 }
1463
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001464 /**
1465 * Sessions automatically watch for requests that all system UI be closed (such as when
1466 * the user presses HOME), which will appear here. The default implementation always
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001467 * calls {@link #hide}.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001468 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001469 public void onCloseSystemDialogs() {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001470 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001471 }
1472
Jorim Jaggi19695d92015-07-20 15:51:40 -07001473 /**
1474 * Called when the lockscreen was shown.
1475 */
1476 public void onLockscreenShown() {
1477 hide();
1478 }
1479
Dianne Hackborn1e383822015-04-10 14:02:33 -07001480 @Override
1481 public void onConfigurationChanged(Configuration newConfig) {
1482 }
1483
1484 @Override
1485 public void onLowMemory() {
1486 }
1487
1488 @Override
1489 public void onTrimMemory(int level) {
1490 }
1491
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001492 /**
1493 * Compute the interesting insets into your UI. The default implementation
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001494 * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height
1495 * of the window, meaning it should not adjust content underneath. The default touchable
1496 * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch
1497 * events within its window frame.
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001498 *
1499 * @param outInsets Fill in with the current UI insets.
1500 */
1501 public void onComputeInsets(Insets outInsets) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001502 outInsets.contentInsets.left = 0;
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001503 outInsets.contentInsets.bottom = 0;
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001504 outInsets.contentInsets.right = 0;
1505 View decor = getWindow().getWindow().getDecorView();
1506 outInsets.contentInsets.top = decor.getHeight();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001507 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
1508 outInsets.touchableRegion.setEmpty();
1509 }
1510
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001511 /**
1512 * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
1513 * has actually started.
1514 *
1515 * @param intent The original {@link Intent} supplied to
1516 * {@link #startVoiceActivity(android.content.Intent)}.
1517 * @param taskId Unique ID of the now running task.
1518 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001519 public void onTaskStarted(Intent intent, int taskId) {
1520 }
1521
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001522 /**
1523 * Called when the last activity of a task initiated by
1524 * {@link #startVoiceActivity(android.content.Intent)} has finished. The default
1525 * implementation calls {@link #finish()} on the assumption that this represents
1526 * the completion of a voice action. You can override the implementation if you would
1527 * like a different behavior.
1528 *
1529 * @param intent The original {@link Intent} supplied to
1530 * {@link #startVoiceActivity(android.content.Intent)}.
1531 * @param taskId Unique ID of the finished task.
1532 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001533 public void onTaskFinished(Intent intent, int taskId) {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001534 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001535 }
1536
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001537 /**
1538 * Request to query for what extended commands the session supports.
1539 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001540 * @param commands An array of commands that are being queried.
1541 * @return Return an array of booleans indicating which of each entry in the
1542 * command array is supported. A true entry in the array indicates the command
1543 * is supported; false indicates it is not. The default implementation returns
1544 * an array of all false entries.
1545 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001546 public boolean[] onGetSupportedCommands(String[] commands) {
Dianne Hackborn593334a2015-06-30 14:38:17 -07001547 return new boolean[commands.length];
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001548 }
1549
1550 /**
1551 * Request to confirm with the user before proceeding with an unrecoverable operation,
1552 * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
1553 * VoiceInteractor.ConfirmationRequest}.
1554 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001555 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001556 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001557 public void onRequestConfirmation(ConfirmationRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001558 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001559
1560 /**
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001561 * Request for the user to pick one of N options, corresponding to a
1562 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
1563 *
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001564 * @param request The active request.
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001565 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001566 public void onRequestPickOption(PickOptionRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001567 }
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001568
1569 /**
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001570 * Request to complete the voice interaction session because the voice activity successfully
1571 * completed its interaction using voice. Corresponds to
1572 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
1573 * VoiceInteractor.CompleteVoiceRequest}. The default implementation just sends an empty
1574 * confirmation back to allow the activity to exit.
1575 *
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001576 * @param request The active request.
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001577 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001578 public void onRequestCompleteVoice(CompleteVoiceRequest request) {
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001579 }
1580
1581 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001582 * Request to abort the voice interaction session because the voice activity can not
1583 * complete its interaction using voice. Corresponds to
1584 * {@link android.app.VoiceInteractor.AbortVoiceRequest
1585 * VoiceInteractor.AbortVoiceRequest}. The default implementation just sends an empty
1586 * confirmation back to allow the activity to exit.
1587 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001588 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001589 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001590 public void onRequestAbortVoice(AbortVoiceRequest request) {
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001591 }
1592
1593 /**
1594 * Process an arbitrary extended command from the caller,
1595 * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
1596 * VoiceInteractor.CommandRequest}.
1597 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001598 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001599 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001600 public void onRequestCommand(CommandRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001601 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001602
1603 /**
Dianne Hackborn593334a2015-06-30 14:38:17 -07001604 * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001605 * that was previously delivered to {@link #onRequestConfirmation},
1606 * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1607 * or {@link #onRequestCommand}.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001608 *
1609 * @param request The request that is being canceled.
1610 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001611 public void onCancelRequest(Request request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001612 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -07001613
1614 /**
1615 * Print the Service's state into the given stream. This gets invoked by
1616 * {@link VoiceInteractionSessionService} when its Service
1617 * {@link android.app.Service#dump} method is called.
1618 *
1619 * @param prefix Text to print at the front of each line.
1620 * @param fd The raw file descriptor that the dump is being sent to.
1621 * @param writer The PrintWriter to which you should dump your state. This will be
1622 * closed for you after you return.
1623 * @param args additional arguments to the dump request.
1624 */
1625 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
1626 writer.print(prefix); writer.print("mToken="); writer.println(mToken);
1627 writer.print(prefix); writer.print("mTheme=#"); writer.println(Integer.toHexString(mTheme));
1628 writer.print(prefix); writer.print("mInitialized="); writer.println(mInitialized);
1629 writer.print(prefix); writer.print("mWindowAdded="); writer.print(mWindowAdded);
1630 writer.print(" mWindowVisible="); writer.println(mWindowVisible);
1631 writer.print(prefix); writer.print("mWindowWasVisible="); writer.print(mWindowWasVisible);
1632 writer.print(" mInShowWindow="); writer.println(mInShowWindow);
1633 if (mActiveRequests.size() > 0) {
1634 writer.print(prefix); writer.println("Active requests:");
1635 String innerPrefix = prefix + " ";
1636 for (int i=0; i<mActiveRequests.size(); i++) {
1637 Request req = mActiveRequests.valueAt(i);
1638 writer.print(prefix); writer.print(" #"); writer.print(i);
1639 writer.print(": ");
1640 writer.println(req);
1641 req.dump(innerPrefix, fd, writer, args);
1642
1643 }
1644 }
1645 }
Dianne Hackborn91097de2014-04-04 18:02:06 -07001646}