blob: 6ff9fe74859d90f51a1562416bcda9545ebc47ca [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 Yamasani0af6fa72016-01-17 15:36:19 -080080 static final boolean DEBUG = true;
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
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700113 final Context mContext;
114 final HandlerCaller mHandlerCaller;
115
116 final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
117
118 IVoiceInteractionManagerService mSystemService;
119 IBinder mToken;
120
121 int mTheme = 0;
122 LayoutInflater mInflater;
123 TypedArray mThemeAttrs;
124 View mRootView;
125 FrameLayout mContentFrame;
126 SoftInputWindow mWindow;
127
128 boolean mInitialized;
129 boolean mWindowAdded;
130 boolean mWindowVisible;
131 boolean mWindowWasVisible;
132 boolean mInShowWindow;
133
134 final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
135
136 final Insets mTmpInsets = new Insets();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700137
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700138 final WeakReference<VoiceInteractionSession> mWeakRef
139 = new WeakReference<VoiceInteractionSession>(this);
140
Dianne Hackborn91097de2014-04-04 18:02:06 -0700141 final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
142 @Override
143 public IVoiceInteractorRequest startConfirmation(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700144 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700145 ConfirmationRequest request = new ConfirmationRequest(callingPackage,
146 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
147 prompt, extras);
148 addRequest(request);
149 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_CONFIRMATION,
150 request));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700151 return request.mInterface;
152 }
153
154 @Override
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700155 public IVoiceInteractorRequest startPickOption(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700156 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt,
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700157 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700158 PickOptionRequest request = new PickOptionRequest(callingPackage,
159 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
160 prompt, options, extras);
161 addRequest(request);
162 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_PICK_OPTION,
163 request));
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700164 return request.mInterface;
165 }
166
167 @Override
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700168 public IVoiceInteractorRequest startCompleteVoice(String callingPackage,
James Cook6cf39752015-06-04 14:18:43 -0700169 IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700170 CompleteVoiceRequest request = new CompleteVoiceRequest(callingPackage,
171 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
172 message, extras);
173 addRequest(request);
174 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMPLETE_VOICE,
175 request));
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700176 return request.mInterface;
177 }
178
179 @Override
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700180 public IVoiceInteractorRequest startAbortVoice(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 AbortVoiceRequest request = new AbortVoiceRequest(callingPackage,
183 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
184 message, extras);
185 addRequest(request);
186 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_ABORT_VOICE,
187 request));
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700188 return request.mInterface;
189 }
190
191 @Override
Dianne Hackborn91097de2014-04-04 18:02:06 -0700192 public IVoiceInteractorRequest startCommand(String callingPackage,
193 IVoiceInteractorCallback callback, String command, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700194 CommandRequest request = new CommandRequest(callingPackage,
195 Binder.getCallingUid(), callback, VoiceInteractionSession.this,
196 command, extras);
Dianne Hackborn593334a2015-06-30 14:38:17 -0700197 addRequest(request);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700198 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMMAND,
199 request));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700200 return request.mInterface;
201 }
202
203 @Override
204 public boolean[] supportsCommands(String callingPackage, String[] commands) {
205 Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700206 0, commands, null);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700207 SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
208 if (args != null) {
209 boolean[] res = (boolean[])args.arg1;
210 args.recycle();
211 return res;
212 }
213 return new boolean[commands.length];
214 }
215 };
216
217 final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700218 @Override
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700219 public void show(Bundle sessionArgs, int flags,
220 IVoiceInteractionSessionShowCallback showCallback) {
221 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_SHOW,
222 flags, sessionArgs, showCallback));
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800223 }
224
225 @Override
226 public void hide() {
227 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
228 }
229
230 @Override
Dianne Hackborn782d4982015-07-08 17:36:37 -0700231 public void handleAssist(final Bundle data, final AssistStructure structure,
232 final AssistContent content) {
Dianne Hackborn5688b032015-04-02 18:25:35 -0700233 // We want to pre-warm the AssistStructure before handing it off to the main
Dianne Hackborn782d4982015-07-08 17:36:37 -0700234 // thread. We also want to do this on a separate thread, so that if the app
235 // is for some reason slow (due to slow filling in of async children in the
236 // structure), we don't block other incoming IPCs (such as the screenshot) to
237 // us (since we are a oneway interface, they get serialized). (Okay?)
238 Thread retriever = new Thread("AssistStructure retriever") {
239 @Override
240 public void run() {
241 Throwable failure = null;
242 if (structure != null) {
243 try {
244 structure.ensureData();
245 } catch (Throwable e) {
246 Log.w(TAG, "Failure retrieving AssistStructure", e);
247 failure = e;
248 }
249 }
250 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_HANDLE_ASSIST,
251 data, failure == null ? structure : null, failure, content));
252 }
253 };
254 retriever.start();
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800255 }
256
257 @Override
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700258 public void handleScreenshot(Bitmap screenshot) {
259 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_SCREENSHOT,
260 screenshot));
261 }
262
263 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700264 public void taskStarted(Intent intent, int taskId) {
265 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
266 taskId, intent));
267 }
268
269 @Override
270 public void taskFinished(Intent intent, int taskId) {
271 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
272 taskId, intent));
273 }
274
275 @Override
276 public void closeSystemDialogs() {
277 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
278 }
279
280 @Override
Jorim Jaggi19695d92015-07-20 15:51:40 -0700281 public void onLockscreenShown() {
282 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_ON_LOCKSCREEN_SHOWN));
283 }
284
285 @Override
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700286 public void destroy() {
287 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
288 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700289 };
290
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700291 /**
292 * Base class representing a request from a voice-driver app to perform a particular
293 * voice operation with the user. See related subclasses for the types of requests
294 * that are possible.
295 */
Dianne Hackborn593334a2015-06-30 14:38:17 -0700296 public static class Request {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700297 final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
298 @Override
299 public void cancel() throws RemoteException {
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700300 VoiceInteractionSession session = mSession.get();
301 if (session != null) {
302 session.mHandlerCaller.sendMessage(
303 session.mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
304 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700305 }
306 };
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700307 final String mCallingPackage;
308 final int mCallingUid;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700309 final IVoiceInteractorCallback mCallback;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700310 final WeakReference<VoiceInteractionSession> mSession;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700311 final Bundle mExtras;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700312
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700313 Request(String packageName, int uid, IVoiceInteractorCallback callback,
314 VoiceInteractionSession session, Bundle extras) {
315 mCallingPackage = packageName;
316 mCallingUid = uid;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700317 mCallback = callback;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700318 mSession = session.mWeakRef;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700319 mExtras = extras;
320 }
321
322 /**
323 * Return the uid of the application that initiated the request.
324 */
325 public int getCallingUid() {
326 return mCallingUid;
327 }
328
329 /**
330 * Return the package name of the application that initiated the request.
331 */
332 public String getCallingPackage() {
333 return mCallingPackage;
334 }
335
336 /**
337 * Return any additional extra information that was supplied as part of the request.
338 */
339 public Bundle getExtras() {
340 return mExtras;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700341 }
342
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700343 /**
344 * Check whether this request is currently active. A request becomes inactive after
345 * calling {@link #cancel} or a final result method that completes the request. After
346 * this point, further interactions with the request will result in
347 * {@link java.lang.IllegalStateException} errors; you should not catch these errors,
348 * but can use this method if you need to determine the state of the request. Returns
349 * true if the request is still active.
350 */
351 public boolean isActive() {
352 VoiceInteractionSession session = mSession.get();
353 if (session == null) {
354 return false;
355 }
356 return session.isRequestActive(mInterface.asBinder());
357 }
358
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700359 void finishRequest() {
360 VoiceInteractionSession session = mSession.get();
361 if (session == null) {
362 throw new IllegalStateException("VoiceInteractionSession has been destroyed");
363 }
364 Request req = session.removeRequest(mInterface.asBinder());
365 if (req == null) {
366 throw new IllegalStateException("Request not active: " + this);
367 } else if (req != this) {
368 throw new IllegalStateException("Current active request " + req
369 + " not same as calling request " + this);
370 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700371 }
372
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700373 /**
Dianne Hackborn593334a2015-06-30 14:38:17 -0700374 * Ask the app to cancel this current request.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700375 * This also finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700376 */
377 public void cancel() {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700378 try {
379 if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700380 finishRequest();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700381 mCallback.deliverCancel(mInterface);
382 } catch (RemoteException e) {
383 }
384 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700385
386 @Override
387 public String toString() {
388 StringBuilder sb = new StringBuilder(128);
389 DebugUtils.buildShortClassTag(this, sb);
390 sb.append(" ");
391 sb.append(mInterface.asBinder());
392 sb.append(" pkg=");
393 sb.append(mCallingPackage);
394 sb.append(" uid=");
395 UserHandle.formatUid(sb, mCallingUid);
396 sb.append('}');
397 return sb.toString();
398 }
399
400 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
401 writer.print(prefix); writer.print("mInterface=");
402 writer.println(mInterface.asBinder());
403 writer.print(prefix); writer.print("mCallingPackage="); writer.print(mCallingPackage);
404 writer.print(" mCallingUid="); UserHandle.formatUid(writer, mCallingUid);
405 writer.println();
406 writer.print(prefix); writer.print("mCallback=");
407 writer.println(mCallback.asBinder());
408 if (mExtras != null) {
409 writer.print(prefix); writer.print("mExtras=");
410 writer.println(mExtras);
411 }
412 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700413 }
414
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700415 /**
416 * A request for confirmation from the user of an operation, as per
417 * {@link android.app.VoiceInteractor.ConfirmationRequest
418 * VoiceInteractor.ConfirmationRequest}.
419 */
420 public static final class ConfirmationRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700421 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700422
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700423 ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700424 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700425 super(packageName, uid, callback, session, extras);
426 mPrompt = prompt;
427 }
428
429 /**
430 * Return the prompt informing the user of what will happen, as per
431 * {@link android.app.VoiceInteractor.ConfirmationRequest
432 * VoiceInteractor.ConfirmationRequest}.
433 */
James Cook6cf39752015-06-04 14:18:43 -0700434 @Nullable
435 public VoiceInteractor.Prompt getVoicePrompt() {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700436 return mPrompt;
437 }
438
439 /**
James Cook6cf39752015-06-04 14:18:43 -0700440 * Return the prompt informing the user of what will happen, as per
441 * {@link android.app.VoiceInteractor.ConfirmationRequest
442 * VoiceInteractor.ConfirmationRequest}.
443 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
444 */
445 @Nullable
446 public CharSequence getPrompt() {
447 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
448 }
449
450 /**
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700451 * Report that the voice interactor has confirmed the operation with the user, resulting
452 * in a call to
453 * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult
454 * VoiceInteractor.ConfirmationRequest.onConfirmationResult}.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700455 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700456 */
457 public void sendConfirmationResult(boolean confirmed, Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700458 try {
459 if (DEBUG) Log.d(TAG, "sendConfirmationResult: req=" + mInterface
460 + " confirmed=" + confirmed + " result=" + result);
461 finishRequest();
462 mCallback.deliverConfirmationResult(mInterface, confirmed, result);
463 } catch (RemoteException e) {
464 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700465 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700466
467 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
468 super.dump(prefix, fd, writer, args);
469 writer.print(prefix); writer.print("mPrompt=");
470 writer.println(mPrompt);
471 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700472 }
473
474 /**
475 * A request for the user to pick from a set of option, as per
476 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
477 */
478 public static final class PickOptionRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700479 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700480 final VoiceInteractor.PickOptionRequest.Option[] mOptions;
481
482 PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700483 VoiceInteractionSession session, VoiceInteractor.Prompt prompt,
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700484 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
485 super(packageName, uid, callback, session, extras);
486 mPrompt = prompt;
487 mOptions = options;
488 }
489
490 /**
491 * Return the prompt informing the user of what they are picking, as per
492 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
493 */
James Cook6cf39752015-06-04 14:18:43 -0700494 @Nullable
495 public VoiceInteractor.Prompt getVoicePrompt() {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700496 return mPrompt;
497 }
498
499 /**
James Cook6cf39752015-06-04 14:18:43 -0700500 * Return the prompt informing the user of what they are picking, as per
501 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
502 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
503 */
504 @Nullable
505 public CharSequence getPrompt() {
506 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
507 }
508
509 /**
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700510 * Return the set of options the user is picking from, as per
511 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
512 */
513 public VoiceInteractor.PickOptionRequest.Option[] getOptions() {
514 return mOptions;
515 }
516
Dianne Hackborn593334a2015-06-30 14:38:17 -0700517 void sendPickOptionResult(boolean finished,
518 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
519 try {
520 if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface
521 + " finished=" + finished + " selections=" + selections
522 + " result=" + result);
523 if (finished) {
524 finishRequest();
525 }
526 mCallback.deliverPickOptionResult(mInterface, finished, selections, result);
527 } catch (RemoteException e) {
528 }
529 }
530
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700531 /**
532 * Report an intermediate option selection from the request, without completing it (the
533 * request is still active and the app is waiting for the final option selection),
534 * resulting in a call to
535 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
536 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
537 */
538 public void sendIntermediatePickOptionResult(
539 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
540 sendPickOptionResult(false, selections, result);
541 }
542
543 /**
544 * Report the final option selection for the request, completing the request
545 * and resulting in a call to
546 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
547 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700548 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700549 */
550 public void sendPickOptionResult(
551 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
552 sendPickOptionResult(true, selections, result);
553 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700554
555 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
556 super.dump(prefix, fd, writer, args);
557 writer.print(prefix); writer.print("mPrompt=");
558 writer.println(mPrompt);
559 if (mOptions != null) {
560 writer.print(prefix); writer.println("Options:");
561 for (int i=0; i<mOptions.length; i++) {
562 VoiceInteractor.PickOptionRequest.Option op = mOptions[i];
563 writer.print(prefix); writer.print(" #"); writer.print(i); writer.println(":");
564 writer.print(prefix); writer.print(" mLabel=");
565 writer.println(op.getLabel());
566 writer.print(prefix); writer.print(" mIndex=");
567 writer.println(op.getIndex());
568 if (op.countSynonyms() > 0) {
569 writer.print(prefix); writer.println(" Synonyms:");
570 for (int j=0; j<op.countSynonyms(); j++) {
571 writer.print(prefix); writer.print(" #"); writer.print(j);
572 writer.print(": "); writer.println(op.getSynonymAt(j));
573 }
574 }
575 if (op.getExtras() != null) {
576 writer.print(prefix); writer.print(" mExtras=");
577 writer.println(op.getExtras());
578 }
579 }
580 }
581 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700582 }
583
584 /**
585 * A request to simply inform the user that the voice operation has completed, as per
586 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
587 * VoiceInteractor.CompleteVoiceRequest}.
588 */
589 public static final class CompleteVoiceRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700590 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700591
592 CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700593 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700594 super(packageName, uid, callback, session, extras);
James Cook6cf39752015-06-04 14:18:43 -0700595 mPrompt = prompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700596 }
597
598 /**
599 * Return the message informing the user of the completion, as per
600 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
601 * VoiceInteractor.CompleteVoiceRequest}.
602 */
James Cook6cf39752015-06-04 14:18:43 -0700603 @Nullable
604 public VoiceInteractor.Prompt getVoicePrompt() {
605 return mPrompt;
606 }
607
608 /**
609 * Return the message informing the user of the completion, as per
610 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
611 * VoiceInteractor.CompleteVoiceRequest}.
612 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
613 */
614 @Nullable
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700615 public CharSequence getMessage() {
James Cook6cf39752015-06-04 14:18:43 -0700616 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700617 }
618
619 /**
620 * Report that the voice interactor has finished completing the voice operation, resulting
621 * in a call to
622 * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult
623 * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700624 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700625 */
626 public void sendCompleteResult(Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700627 try {
628 if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface
629 + " result=" + result);
630 finishRequest();
631 mCallback.deliverCompleteVoiceResult(mInterface, result);
632 } catch (RemoteException e) {
633 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700634 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700635
636 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
637 super.dump(prefix, fd, writer, args);
638 writer.print(prefix); writer.print("mPrompt=");
639 writer.println(mPrompt);
640 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700641 }
642
643 /**
644 * A request to report that the current user interaction can not be completed with voice, as per
645 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
646 */
647 public static final class AbortVoiceRequest extends Request {
James Cook6cf39752015-06-04 14:18:43 -0700648 final VoiceInteractor.Prompt mPrompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700649
650 AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
James Cook6cf39752015-06-04 14:18:43 -0700651 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700652 super(packageName, uid, callback, session, extras);
James Cook6cf39752015-06-04 14:18:43 -0700653 mPrompt = prompt;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700654 }
655
656 /**
657 * Return the message informing the user of the problem, as per
658 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
659 */
James Cook6cf39752015-06-04 14:18:43 -0700660 @Nullable
661 public VoiceInteractor.Prompt getVoicePrompt() {
662 return mPrompt;
663 }
664
665 /**
666 * Return the message informing the user of the problem, as per
667 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
668 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
669 */
670 @Nullable
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700671 public CharSequence getMessage() {
James Cook6cf39752015-06-04 14:18:43 -0700672 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700673 }
674
675 /**
676 * Report that the voice interactor has finished aborting the voice operation, resulting
677 * in a call to
678 * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700679 * VoiceInteractor.AbortVoiceRequest.onAbortResult}. This finishes the request (it
680 * is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700681 */
682 public void sendAbortResult(Bundle result) {
Dianne Hackborn593334a2015-06-30 14:38:17 -0700683 try {
684 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
685 + " result=" + result);
686 finishRequest();
687 mCallback.deliverAbortVoiceResult(mInterface, result);
688 } catch (RemoteException e) {
689 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700690 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700691
692 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
693 super.dump(prefix, fd, writer, args);
694 writer.print(prefix); writer.print("mPrompt=");
695 writer.println(mPrompt);
696 }
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700697 }
698
699 /**
700 * A generic vendor-specific request, as per
701 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
702 */
703 public static final class CommandRequest extends Request {
704 final String mCommand;
705
706 CommandRequest(String packageName, int uid, IVoiceInteractorCallback callback,
707 VoiceInteractionSession session, String command, Bundle extras) {
708 super(packageName, uid, callback, session, extras);
709 mCommand = command;
710 }
711
712 /**
713 * Return the command that is being executed, as per
714 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
715 */
716 public String getCommand() {
717 return mCommand;
718 }
719
Dianne Hackborn593334a2015-06-30 14:38:17 -0700720 void sendCommandResult(boolean finished, Bundle result) {
721 try {
722 if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
723 + " result=" + result);
724 if (finished) {
725 finishRequest();
726 }
727 mCallback.deliverCommandResult(mInterface, finished, result);
728 } catch (RemoteException e) {
729 }
730 }
731
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700732 /**
733 * Report an intermediate result of the request, without completing it (the request
734 * is still active and the app is waiting for the final result), resulting in a call to
735 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
736 * VoiceInteractor.CommandRequest.onCommandResult} with false for isCompleted.
737 */
738 public void sendIntermediateResult(Bundle result) {
739 sendCommandResult(false, result);
740 }
741
742 /**
743 * Report the final result of the request, completing the request and resulting in a call to
744 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
745 * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted.
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700746 * This finishes the request (it is no longer active).
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700747 */
748 public void sendResult(Bundle result) {
749 sendCommandResult(true, result);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700750 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700751
752 void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
753 super.dump(prefix, fd, writer, args);
754 writer.print(prefix); writer.print("mCommand=");
755 writer.println(mCommand);
756 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700757 }
758
759 static final int MSG_START_CONFIRMATION = 1;
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700760 static final int MSG_START_PICK_OPTION = 2;
761 static final int MSG_START_COMPLETE_VOICE = 3;
762 static final int MSG_START_ABORT_VOICE = 4;
763 static final int MSG_START_COMMAND = 5;
764 static final int MSG_SUPPORTS_COMMANDS = 6;
765 static final int MSG_CANCEL = 7;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700766
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700767 static final int MSG_TASK_STARTED = 100;
768 static final int MSG_TASK_FINISHED = 101;
769 static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
770 static final int MSG_DESTROY = 103;
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800771 static final int MSG_HANDLE_ASSIST = 104;
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700772 static final int MSG_HANDLE_SCREENSHOT = 105;
773 static final int MSG_SHOW = 106;
774 static final int MSG_HIDE = 107;
Jorim Jaggi19695d92015-07-20 15:51:40 -0700775 static final int MSG_ON_LOCKSCREEN_SHOWN = 108;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700776
777 class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
Dianne Hackborn91097de2014-04-04 18:02:06 -0700778 @Override
779 public void executeMessage(Message msg) {
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700780 SomeArgs args = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700781 switch (msg.what) {
782 case MSG_START_CONFIRMATION:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700783 if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
784 onRequestConfirmation((ConfirmationRequest) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700785 break;
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700786 case MSG_START_PICK_OPTION:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700787 if (DEBUG) Log.d(TAG, "onPickOption: req=" + msg.obj);
788 onRequestPickOption((PickOptionRequest) msg.obj);
Dianne Hackborn3d07c942015-03-13 18:02:54 -0700789 break;
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700790 case MSG_START_COMPLETE_VOICE:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700791 if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + msg.obj);
792 onRequestCompleteVoice((CompleteVoiceRequest) msg.obj);
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -0700793 break;
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700794 case MSG_START_ABORT_VOICE:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700795 if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + msg.obj);
796 onRequestAbortVoice((AbortVoiceRequest) msg.obj);
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700797 break;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700798 case MSG_START_COMMAND:
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700799 if (DEBUG) Log.d(TAG, "onCommand: req=" + msg.obj);
800 onRequestCommand((CommandRequest) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700801 break;
802 case MSG_SUPPORTS_COMMANDS:
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700803 args = (SomeArgs)msg.obj;
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700804 if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
805 args.arg1 = onGetSupportedCommands((String[]) args.arg1);
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700806 args.complete();
807 args = null;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700808 break;
809 case MSG_CANCEL:
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800810 if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700811 onCancelRequest((Request) msg.obj);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700812 break;
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700813 case MSG_TASK_STARTED:
814 if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
815 + " taskId=" + msg.arg1);
816 onTaskStarted((Intent) msg.obj, msg.arg1);
817 break;
818 case MSG_TASK_FINISHED:
819 if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
820 + " taskId=" + msg.arg1);
821 onTaskFinished((Intent) msg.obj, msg.arg1);
822 break;
823 case MSG_CLOSE_SYSTEM_DIALOGS:
824 if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
825 onCloseSystemDialogs();
826 break;
827 case MSG_DESTROY:
828 if (DEBUG) Log.d(TAG, "doDestroy");
829 doDestroy();
830 break;
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800831 case MSG_HANDLE_ASSIST:
Dianne Hackborn09d57fe2015-05-27 18:05:52 -0700832 args = (SomeArgs)msg.obj;
833 if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
834 + " structure=" + args.arg2 + " content=" + args.arg3);
Dianne Hackborn782d4982015-07-08 17:36:37 -0700835 doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
836 (Throwable) args.arg3, (AssistContent) args.arg4);
Dianne Hackbornae6688b2015-02-11 17:02:41 -0800837 break;
Dianne Hackborn27eac1d2015-03-16 17:15:53 -0700838 case MSG_HANDLE_SCREENSHOT:
839 if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
840 onHandleScreenshot((Bitmap) msg.obj);
841 break;
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800842 case MSG_SHOW:
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700843 args = (SomeArgs)msg.obj;
844 if (DEBUG) Log.d(TAG, "doShow: args=" + args.arg1
845 + " flags=" + msg.arg1
846 + " showCallback=" + args.arg2);
847 doShow((Bundle) args.arg1, msg.arg1,
848 (IVoiceInteractionSessionShowCallback) args.arg2);
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800849 break;
850 case MSG_HIDE:
851 if (DEBUG) Log.d(TAG, "doHide");
852 doHide();
853 break;
Jorim Jaggi19695d92015-07-20 15:51:40 -0700854 case MSG_ON_LOCKSCREEN_SHOWN:
855 if (DEBUG) Log.d(TAG, "onLockscreenShown");
856 onLockscreenShown();
857 break;
Dianne Hackborn91097de2014-04-04 18:02:06 -0700858 }
Dianne Hackbornd0a15902015-07-15 11:18:09 -0700859 if (args != null) {
860 args.recycle();
861 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700862 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700863
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700864 @Override
865 public void onBackPressed() {
866 VoiceInteractionSession.this.onBackPressed();
867 }
868 }
869
870 final MyCallbacks mCallbacks = new MyCallbacks();
871
872 /**
873 * Information about where interesting parts of the input method UI appear.
874 */
875 public static final class Insets {
876 /**
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700877 * This is the part of the UI that is the main content. It is
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700878 * used to determine the basic space needed, to resize/pan the
879 * application behind. It is assumed that this inset does not
880 * change very much, since any change will cause a full resize/pan
881 * of the application behind. This value is relative to the top edge
882 * of the input method window.
883 */
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700884 public final Rect contentInsets = new Rect();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700885
886 /**
887 * This is the region of the UI that is touchable. It is used when
888 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
889 * The region should be specified relative to the origin of the window frame.
890 */
891 public final Region touchableRegion = new Region();
892
893 /**
894 * Option for {@link #touchableInsets}: the entire window frame
895 * can be touched.
896 */
897 public static final int TOUCHABLE_INSETS_FRAME
898 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
899
900 /**
901 * Option for {@link #touchableInsets}: the area inside of
902 * the content insets can be touched.
903 */
904 public static final int TOUCHABLE_INSETS_CONTENT
905 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
906
907 /**
908 * Option for {@link #touchableInsets}: the region specified by
909 * {@link #touchableRegion} can be touched.
910 */
911 public static final int TOUCHABLE_INSETS_REGION
912 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
913
914 /**
915 * Determine which area of the window is touchable by the user. May
916 * be one of: {@link #TOUCHABLE_INSETS_FRAME},
917 * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
918 */
919 public int touchableInsets;
920 }
921
922 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
923 new ViewTreeObserver.OnComputeInternalInsetsListener() {
924 public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
925 onComputeInsets(mTmpInsets);
Dianne Hackborne30e02f2014-05-27 18:24:45 -0700926 info.contentInsets.set(mTmpInsets.contentInsets);
927 info.visibleInsets.set(mTmpInsets.contentInsets);
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700928 info.touchableRegion.set(mTmpInsets.touchableRegion);
929 info.setTouchableInsets(mTmpInsets.touchableInsets);
930 }
931 };
Dianne Hackborn91097de2014-04-04 18:02:06 -0700932
933 public VoiceInteractionSession(Context context) {
934 this(context, new Handler());
935 }
936
937 public VoiceInteractionSession(Context context, Handler handler) {
938 mContext = context;
939 mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700940 mCallbacks, true);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700941 }
942
Dianne Hackbornd59a5d52015-04-04 14:52:14 -0700943 public Context getContext() {
944 return mContext;
945 }
946
Dianne Hackborn2ee5c362015-05-29 17:58:53 -0700947 void addRequest(Request req) {
Dianne Hackborn1b4447f2015-07-20 14:49:58 -0700948 synchronized (this) {
949 mActiveRequests.put(req.mInterface.asBinder(), req);
950 }
951 }
952
953 boolean isRequestActive(IBinder reqInterface) {
954 synchronized (this) {
955 return mActiveRequests.containsKey(reqInterface);
956 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -0700957 }
958
959 Request removeRequest(IBinder reqInterface) {
960 synchronized (this) {
Andreas Gampe8ef92bd2015-03-17 21:22:49 -0700961 return mActiveRequests.remove(reqInterface);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700962 }
963 }
964
Dianne Hackborn593334a2015-06-30 14:38:17 -0700965 void doCreate(IVoiceInteractionManagerService service, IBinder token) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700966 mSystemService = service;
967 mToken = token;
Dianne Hackborn593334a2015-06-30 14:38:17 -0700968 onCreate();
Dianne Hackbornc03c9162014-05-02 10:45:59 -0700969 }
970
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700971 void doShow(Bundle args, int flags, final IVoiceInteractionSessionShowCallback showCallback) {
Dianne Hackbornffeecb12015-02-25 11:08:11 -0800972 if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
973 + " mWindowVisible=" + mWindowVisible);
974
975 if (mInShowWindow) {
976 Log.w(TAG, "Re-entrance in to showWindow");
977 return;
978 }
979
980 try {
981 mInShowWindow = true;
982 if (!mWindowVisible) {
983 if (!mWindowAdded) {
984 mWindowAdded = true;
985 View v = onCreateContentView();
986 if (v != null) {
987 setContentView(v);
988 }
989 }
990 }
991 onShow(args, flags);
992 if (!mWindowVisible) {
993 mWindowVisible = true;
994 mWindow.show();
995 }
Jorim Jaggi225d3b52015-04-01 11:18:57 -0700996 if (showCallback != null) {
997 mRootView.invalidate();
998 mRootView.getViewTreeObserver().addOnPreDrawListener(
999 new ViewTreeObserver.OnPreDrawListener() {
1000 @Override
1001 public boolean onPreDraw() {
1002 mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
1003 try {
1004 showCallback.onShown();
1005 } catch (RemoteException e) {
1006 Log.w(TAG, "Error calling onShown", e);
1007 }
1008 return true;
1009 }
1010 });
1011 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001012 } finally {
1013 mWindowWasVisible = true;
1014 mInShowWindow = false;
1015 }
1016 }
1017
1018 void doHide() {
1019 if (mWindowVisible) {
1020 mWindow.hide();
1021 mWindowVisible = false;
1022 onHide();
1023 }
1024 }
1025
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001026 void doDestroy() {
Dianne Hackborn9a35d782014-08-07 12:34:37 -07001027 onDestroy();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001028 if (mInitialized) {
1029 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
1030 mInsetsComputer);
1031 if (mWindowAdded) {
1032 mWindow.dismiss();
1033 mWindowAdded = false;
1034 }
1035 mInitialized = false;
1036 }
1037 }
1038
1039 void initViews() {
1040 mInitialized = true;
1041
1042 mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
1043 mRootView = mInflater.inflate(
1044 com.android.internal.R.layout.voice_interaction_session, null);
1045 mRootView.setSystemUiVisibility(
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001046 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
1047 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001048 mWindow.setContentView(mRootView);
1049 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
1050
1051 mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
1052 }
1053
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001054 /**
Dianne Hackborn1de11862015-07-15 14:20:51 -07001055 * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
1056 * VoiceInteractionService.setDisabledShowContext(int)}.
1057 */
1058 public void setDisabledShowContext(int flags) {
1059 try {
1060 mSystemService.setDisabledShowContext(flags);
1061 } catch (RemoteException e) {
1062 }
1063 }
1064
1065 /**
1066 * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
1067 * VoiceInteractionService.getDisabledShowContext}.
1068 */
1069 public int getDisabledShowContext() {
1070 try {
1071 return mSystemService.getDisabledShowContext();
1072 } catch (RemoteException e) {
1073 return 0;
1074 }
1075 }
1076
1077 /**
Dianne Hackborn17f69352015-07-17 18:04:14 -07001078 * Return which show context flags have been disabled by the user through the system
1079 * settings UI, so the session will never get this data. Returned flags are any combination of
1080 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
1081 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
1082 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. Note that this only tells you about
1083 * global user settings, not about restrictions that may be applied contextual based on
1084 * the current application the user is in or other transient states.
1085 */
1086 public int getUserDisabledShowContext() {
1087 try {
1088 return mSystemService.getUserDisabledShowContext();
1089 } catch (RemoteException e) {
1090 return 0;
1091 }
1092 }
1093
1094 /**
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001095 * Show the UI for this session. This asks the system to go through the process of showing
1096 * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling
1097 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1098 * @param args Arbitrary arguments that will be propagated {@link #onShow}.
1099 * @param flags Indicates additional optional behavior that should be performed. May
Dianne Hackborn1de11862015-07-15 14:20:51 -07001100 * be any combination of
1101 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
1102 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
1103 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001104 * to request that the system generate and deliver assist data on the current foreground
1105 * app as part of showing the session UI.
1106 */
1107 public void show(Bundle args, int flags) {
1108 if (mToken == null) {
1109 throw new IllegalStateException("Can't call before onCreate()");
1110 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001111 try {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001112 mSystemService.showSessionFromSession(mToken, args, flags);
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001113 } catch (RemoteException e) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001114 }
1115 }
1116
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001117 /**
1118 * Hide the session's UI, if currently shown. Call this when you are done with your
1119 * user interaction.
1120 */
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001121 public void hide() {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001122 if (mToken == null) {
1123 throw new IllegalStateException("Can't call before onCreate()");
1124 }
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001125 try {
1126 mSystemService.hideSessionFromSession(mToken);
1127 } catch (RemoteException e) {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001128 }
1129 }
1130
1131 /**
1132 * You can call this to customize the theme used by your IME's window.
1133 * This must be set before {@link #onCreate}, so you
1134 * will typically call it in your constructor with the resource ID
1135 * of your custom theme.
1136 */
1137 public void setTheme(int theme) {
1138 if (mWindow != null) {
1139 throw new IllegalStateException("Must be called before onCreate()");
1140 }
1141 mTheme = theme;
1142 }
1143
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001144 /**
1145 * Ask that a new activity be started for voice interaction. This will create a
1146 * new dedicated task in the activity manager for this voice interaction session;
1147 * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
1148 * will be set for you to make it a new task.
1149 *
1150 * <p>The newly started activity will be displayed to the user in a special way, as
1151 * a layer under the voice interaction UI.</p>
1152 *
1153 * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor}
1154 * through which it can perform voice interactions through your session. These requests
1155 * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands},
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001156 * {@link #onRequestConfirmation}, {@link #onRequestPickOption},
1157 * {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1158 * or {@link #onRequestCommand}
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001159 *
1160 * <p>You will receive a call to {@link #onTaskStarted} when the task starts up
1161 * and {@link #onTaskFinished} when the last activity has finished.
1162 *
1163 * @param intent The Intent to start this voice interaction. The given Intent will
1164 * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
1165 * this is part of a voice interaction.
1166 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001167 public void startVoiceActivity(Intent intent) {
1168 if (mToken == null) {
1169 throw new IllegalStateException("Can't call before onCreate()");
1170 }
1171 try {
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001172 intent.migrateExtraStreamToClipData();
Jeff Sharkey344744b2016-01-28 19:03:30 -07001173 intent.prepareToLeaveProcess(mContext);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001174 int res = mSystemService.startVoiceActivity(mToken, intent,
1175 intent.resolveType(mContext.getContentResolver()));
1176 Instrumentation.checkStartActivityResult(res, intent);
1177 } catch (RemoteException e) {
1178 }
1179 }
1180
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001181 /**
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001182 * Set whether this session will keep the device awake while it is running a voice
1183 * activity. By default, the system holds a wake lock for it while in this state,
1184 * so that it can work even if the screen is off. Setting this to false removes that
1185 * wake lock, allowing the CPU to go to sleep. This is typically used if the
1186 * session decides it has been waiting too long for a response from the user and
1187 * doesn't want to let this continue to drain the battery.
1188 *
1189 * <p>Passing false here will release the wake lock, and you can call later with
1190 * true to re-acquire it. It will also be automatically re-acquired for you each
1191 * time you start a new voice activity task -- that is when you call
1192 * {@link #startVoiceActivity}.</p>
1193 */
1194 public void setKeepAwake(boolean keepAwake) {
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001195 if (mToken == null) {
1196 throw new IllegalStateException("Can't call before onCreate()");
1197 }
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001198 try {
1199 mSystemService.setKeepAwake(mToken, keepAwake);
1200 } catch (RemoteException e) {
1201 }
1202 }
1203
1204 /**
Dianne Hackborn4e88bcd2015-07-01 13:41:03 -07001205 * Request that all system dialogs (and status bar shade etc) be closed, allowing
1206 * access to the session's UI. This will <em>not</em> cause the lock screen to be
1207 * dismissed.
1208 */
1209 public void closeSystemDialogs() {
1210 if (mToken == null) {
1211 throw new IllegalStateException("Can't call before onCreate()");
1212 }
1213 try {
1214 mSystemService.closeSystemDialogs(mToken);
1215 } catch (RemoteException e) {
1216 }
1217 }
1218
1219 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001220 * Convenience for inflating views.
1221 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001222 public LayoutInflater getLayoutInflater() {
1223 return mInflater;
1224 }
1225
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001226 /**
1227 * Retrieve the window being used to show the session's UI.
1228 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001229 public Dialog getWindow() {
1230 return mWindow;
1231 }
1232
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001233 /**
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001234 * Finish the session. This completely destroys the session -- the next time it is shown,
1235 * an entirely new one will be created. You do not normally call this function; instead,
1236 * use {@link #hide} and allow the system to destroy your session if it needs its RAM.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001237 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001238 public void finish() {
1239 if (mToken == null) {
1240 throw new IllegalStateException("Can't call before onCreate()");
1241 }
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001242 try {
1243 mSystemService.finish(mToken);
1244 } catch (RemoteException e) {
1245 }
1246 }
1247
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001248 /**
1249 * Initiatize a new session. At this point you don't know exactly what this
1250 * session will be used for; you will find that out in {@link #onShow}.
1251 */
1252 public void onCreate() {
1253 doOnCreate();
1254 }
1255
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001256 private void doOnCreate() {
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001257 mTheme = mTheme != 0 ? mTheme
1258 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
1259 mInflater = (LayoutInflater)mContext.getSystemService(
1260 Context.LAYOUT_INFLATER_SERVICE);
1261 mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001262 mCallbacks, this, mDispatcherState,
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001263 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
Jorim Jaggi225d3b52015-04-01 11:18:57 -07001264 mWindow.getWindow().addFlags(
1265 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
Stefan Kuhne2f280d062015-06-18 07:20:33 -10001266 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
1267 WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001268 initViews();
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001269 mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001270 mWindow.setToken(mToken);
1271 }
1272
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001273 /**
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001274 * Called when the session UI is going to be shown. This is called after
1275 * {@link #onCreateContentView} (if the session's content UI needed to be created) and
1276 * immediately prior to the window being shown. This may be called while the window
1277 * is already shown, if a show request has come in while it is shown, to allow you to
1278 * update the UI to match the new show arguments.
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001279 *
1280 * @param args The arguments that were supplied to
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001281 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1282 * @param showFlags The show flags originally provided to
1283 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001284 */
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001285 public void onShow(Bundle args, int showFlags) {
1286 }
1287
1288 /**
1289 * Called immediately after stopping to show the session UI.
1290 */
1291 public void onHide() {
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001292 }
1293
1294 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001295 * Last callback to the session as it is being finished.
1296 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001297 public void onDestroy() {
1298 }
1299
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001300 /**
1301 * Hook in which to create the session's UI.
1302 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001303 public View onCreateContentView() {
1304 return null;
1305 }
1306
1307 public void setContentView(View view) {
1308 mContentFrame.removeAllViews();
1309 mContentFrame.addView(view, new FrameLayout.LayoutParams(
1310 ViewGroup.LayoutParams.MATCH_PARENT,
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001311 ViewGroup.LayoutParams.MATCH_PARENT));
Adam Powell41607d52015-06-17 13:37:06 -07001312 mContentFrame.requestApplyInsets();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001313 }
1314
Dianne Hackborn782d4982015-07-08 17:36:37 -07001315 void doOnHandleAssist(Bundle data, AssistStructure structure, Throwable failure,
1316 AssistContent content) {
1317 if (failure != null) {
1318 onAssistStructureFailure(failure);
1319 }
1320 onHandleAssist(data, structure, content);
1321 }
1322
1323 /**
1324 * Called when there has been a failure transferring the {@link AssistStructure} to
1325 * the assistant. This may happen, for example, if the data is too large and results
1326 * in an out of memory exception, or the client has provided corrupt data. This will
1327 * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied
1328 * there afterwards will be null.
1329 *
1330 * @param failure The failure exception that was thrown when building the
1331 * {@link AssistStructure}.
1332 */
1333 public void onAssistStructureFailure(Throwable failure) {
1334 }
1335
1336 /**
1337 * Called to receive data from the application that the user was currently viewing when
Dianne Hackborn17f69352015-07-17 18:04:14 -07001338 * an assist session is started. If the original show request did not specify
1339 * {@link #SHOW_WITH_ASSIST}, this method will not be called.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001340 *
1341 * @param data Arbitrary data supplied by the app through
1342 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
Dianne Hackborn17f69352015-07-17 18:04:14 -07001343 * May be null if assist data has been disabled by the user or device policy.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001344 * @param structure If available, the structure definition of all windows currently
Dianne Hackborn17f69352015-07-17 18:04:14 -07001345 * displayed by the app. May be null if assist data has been disabled by the user
1346 * or device policy; will be an empty stub if the application has disabled assist
1347 * by marking its window as secure.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001348 * @param content Additional content data supplied by the app through
1349 * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
Dianne Hackborn17f69352015-07-17 18:04:14 -07001350 * May be null if assist data has been disabled by the user or device policy; will
1351 * not be automatically filled in with data from the app if the app has marked its
1352 * window as secure.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001353 */
Dianne Hackborn17f69352015-07-17 18:04:14 -07001354 public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure,
1355 @Nullable AssistContent content) {
Dianne Hackborn09d57fe2015-05-27 18:05:52 -07001356 }
1357
Dianne Hackborn782d4982015-07-08 17:36:37 -07001358 /**
1359 * Called to receive a screenshot of what the user was currently viewing when an assist
Dianne Hackborn17f69352015-07-17 18:04:14 -07001360 * session is started. May be null if screenshots are disabled by the user, policy,
1361 * or application. If the original show request did not specify
1362 * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called.
Dianne Hackborn782d4982015-07-08 17:36:37 -07001363 */
Dianne Hackborn17f69352015-07-17 18:04:14 -07001364 public void onHandleScreenshot(@Nullable Bitmap screenshot) {
Dianne Hackborn27eac1d2015-03-16 17:15:53 -07001365 }
1366
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001367 public boolean onKeyDown(int keyCode, KeyEvent event) {
1368 return false;
1369 }
1370
1371 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1372 return false;
1373 }
1374
1375 public boolean onKeyUp(int keyCode, KeyEvent event) {
1376 return false;
1377 }
1378
1379 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
1380 return false;
1381 }
1382
Dianne Hackbornd59a5d52015-04-04 14:52:14 -07001383 /**
1384 * Called when the user presses the back button while focus is in the session UI. Note
1385 * that this will only happen if the session UI has requested input focus in its window;
1386 * otherwise, the back key will go to whatever window has focus and do whatever behavior
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001387 * it normally has there. The default implementation simply calls {@link #hide}.
Dianne Hackbornd59a5d52015-04-04 14:52:14 -07001388 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001389 public void onBackPressed() {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001390 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001391 }
1392
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001393 /**
1394 * Sessions automatically watch for requests that all system UI be closed (such as when
1395 * the user presses HOME), which will appear here. The default implementation always
Dianne Hackborn69c6adc2015-06-02 10:52:59 -07001396 * calls {@link #hide}.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001397 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001398 public void onCloseSystemDialogs() {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001399 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001400 }
1401
Jorim Jaggi19695d92015-07-20 15:51:40 -07001402 /**
1403 * Called when the lockscreen was shown.
1404 */
1405 public void onLockscreenShown() {
1406 hide();
1407 }
1408
Dianne Hackborn1e383822015-04-10 14:02:33 -07001409 @Override
1410 public void onConfigurationChanged(Configuration newConfig) {
1411 }
1412
1413 @Override
1414 public void onLowMemory() {
1415 }
1416
1417 @Override
1418 public void onTrimMemory(int level) {
1419 }
1420
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001421 /**
1422 * Compute the interesting insets into your UI. The default implementation
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001423 * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height
1424 * of the window, meaning it should not adjust content underneath. The default touchable
1425 * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch
1426 * events within its window frame.
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001427 *
1428 * @param outInsets Fill in with the current UI insets.
1429 */
1430 public void onComputeInsets(Insets outInsets) {
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001431 outInsets.contentInsets.left = 0;
Dianne Hackborne30e02f2014-05-27 18:24:45 -07001432 outInsets.contentInsets.bottom = 0;
Dianne Hackbornae6688b2015-02-11 17:02:41 -08001433 outInsets.contentInsets.right = 0;
1434 View decor = getWindow().getWindow().getDecorView();
1435 outInsets.contentInsets.top = decor.getHeight();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001436 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
1437 outInsets.touchableRegion.setEmpty();
1438 }
1439
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001440 /**
1441 * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
1442 * has actually started.
1443 *
1444 * @param intent The original {@link Intent} supplied to
1445 * {@link #startVoiceActivity(android.content.Intent)}.
1446 * @param taskId Unique ID of the now running task.
1447 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001448 public void onTaskStarted(Intent intent, int taskId) {
1449 }
1450
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001451 /**
1452 * Called when the last activity of a task initiated by
1453 * {@link #startVoiceActivity(android.content.Intent)} has finished. The default
1454 * implementation calls {@link #finish()} on the assumption that this represents
1455 * the completion of a voice action. You can override the implementation if you would
1456 * like a different behavior.
1457 *
1458 * @param intent The original {@link Intent} supplied to
1459 * {@link #startVoiceActivity(android.content.Intent)}.
1460 * @param taskId Unique ID of the finished task.
1461 */
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001462 public void onTaskFinished(Intent intent, int taskId) {
Dianne Hackbornffeecb12015-02-25 11:08:11 -08001463 hide();
Dianne Hackbornc03c9162014-05-02 10:45:59 -07001464 }
1465
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001466 /**
1467 * Request to query for what extended commands the session supports.
1468 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001469 * @param commands An array of commands that are being queried.
1470 * @return Return an array of booleans indicating which of each entry in the
1471 * command array is supported. A true entry in the array indicates the command
1472 * is supported; false indicates it is not. The default implementation returns
1473 * an array of all false entries.
1474 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001475 public boolean[] onGetSupportedCommands(String[] commands) {
Dianne Hackborn593334a2015-06-30 14:38:17 -07001476 return new boolean[commands.length];
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001477 }
1478
1479 /**
1480 * Request to confirm with the user before proceeding with an unrecoverable operation,
1481 * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
1482 * VoiceInteractor.ConfirmationRequest}.
1483 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001484 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001485 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001486 public void onRequestConfirmation(ConfirmationRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001487 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001488
1489 /**
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001490 * Request for the user to pick one of N options, corresponding to a
1491 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
1492 *
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001493 * @param request The active request.
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001494 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001495 public void onRequestPickOption(PickOptionRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001496 }
Dianne Hackborn3d07c942015-03-13 18:02:54 -07001497
1498 /**
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001499 * Request to complete the voice interaction session because the voice activity successfully
1500 * completed its interaction using voice. Corresponds to
1501 * {@link android.app.VoiceInteractor.CompleteVoiceRequest
1502 * VoiceInteractor.CompleteVoiceRequest}. The default implementation just sends an empty
1503 * confirmation back to allow the activity to exit.
1504 *
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001505 * @param request The active request.
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001506 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001507 public void onRequestCompleteVoice(CompleteVoiceRequest request) {
Barnaby Jamesd3fdb8b2014-07-07 10:51:06 -07001508 }
1509
1510 /**
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001511 * Request to abort the voice interaction session because the voice activity can not
1512 * complete its interaction using voice. Corresponds to
1513 * {@link android.app.VoiceInteractor.AbortVoiceRequest
1514 * VoiceInteractor.AbortVoiceRequest}. The default implementation just sends an empty
1515 * confirmation back to allow the activity to exit.
1516 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001517 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001518 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001519 public void onRequestAbortVoice(AbortVoiceRequest request) {
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001520 }
1521
1522 /**
1523 * Process an arbitrary extended command from the caller,
1524 * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
1525 * VoiceInteractor.CommandRequest}.
1526 *
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001527 * @param request The active request.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001528 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001529 public void onRequestCommand(CommandRequest request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001530 }
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001531
1532 /**
Dianne Hackborn593334a2015-06-30 14:38:17 -07001533 * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001534 * that was previously delivered to {@link #onRequestConfirmation},
1535 * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1536 * or {@link #onRequestCommand}.
Dianne Hackborna2c076d2014-05-30 16:42:57 -07001537 *
1538 * @param request The request that is being canceled.
1539 */
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001540 public void onCancelRequest(Request request) {
Dianne Hackborn2ee5c362015-05-29 17:58:53 -07001541 }
Dianne Hackborn57dd7372015-07-27 18:11:14 -07001542
1543 /**
1544 * Print the Service's state into the given stream. This gets invoked by
1545 * {@link VoiceInteractionSessionService} when its Service
1546 * {@link android.app.Service#dump} method is called.
1547 *
1548 * @param prefix Text to print at the front of each line.
1549 * @param fd The raw file descriptor that the dump is being sent to.
1550 * @param writer The PrintWriter to which you should dump your state. This will be
1551 * closed for you after you return.
1552 * @param args additional arguments to the dump request.
1553 */
1554 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
1555 writer.print(prefix); writer.print("mToken="); writer.println(mToken);
1556 writer.print(prefix); writer.print("mTheme=#"); writer.println(Integer.toHexString(mTheme));
1557 writer.print(prefix); writer.print("mInitialized="); writer.println(mInitialized);
1558 writer.print(prefix); writer.print("mWindowAdded="); writer.print(mWindowAdded);
1559 writer.print(" mWindowVisible="); writer.println(mWindowVisible);
1560 writer.print(prefix); writer.print("mWindowWasVisible="); writer.print(mWindowWasVisible);
1561 writer.print(" mInShowWindow="); writer.println(mInShowWindow);
1562 if (mActiveRequests.size() > 0) {
1563 writer.print(prefix); writer.println("Active requests:");
1564 String innerPrefix = prefix + " ";
1565 for (int i=0; i<mActiveRequests.size(); i++) {
1566 Request req = mActiveRequests.valueAt(i);
1567 writer.print(prefix); writer.print(" #"); writer.print(i);
1568 writer.print(": ");
1569 writer.println(req);
1570 req.dump(innerPrefix, fd, writer, args);
1571
1572 }
1573 }
1574 }
Dianne Hackborn91097de2014-04-04 18:02:06 -07001575}