VoiceInteractionSession.java revision 17f693520da8977c4a60f5b4be3be035cba7146c
1/** 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 19import android.annotation.Nullable; 20import android.app.Dialog; 21import android.app.Instrumentation; 22import android.app.VoiceInteractor; 23import android.app.assist.AssistContent; 24import android.app.assist.AssistStructure; 25import android.content.ComponentCallbacks2; 26import android.content.Context; 27import android.content.Intent; 28import android.content.res.Configuration; 29import android.content.res.TypedArray; 30import android.graphics.Bitmap; 31import android.graphics.Rect; 32import android.graphics.Region; 33import android.inputmethodservice.SoftInputWindow; 34import android.os.Binder; 35import android.os.Bundle; 36import android.os.Handler; 37import android.os.IBinder; 38import android.os.Message; 39import android.os.RemoteException; 40import android.util.ArrayMap; 41import android.util.Log; 42import android.view.Gravity; 43import android.view.KeyEvent; 44import android.view.LayoutInflater; 45import android.view.View; 46import android.view.ViewGroup; 47import android.view.ViewTreeObserver; 48import android.view.WindowManager; 49import android.widget.FrameLayout; 50import com.android.internal.app.IVoiceInteractionManagerService; 51import com.android.internal.app.IVoiceInteractionSessionShowCallback; 52import com.android.internal.app.IVoiceInteractor; 53import com.android.internal.app.IVoiceInteractorCallback; 54import com.android.internal.app.IVoiceInteractorRequest; 55import com.android.internal.os.HandlerCaller; 56import com.android.internal.os.SomeArgs; 57 58import java.lang.ref.WeakReference; 59 60import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 61 62/** 63 * An active voice interaction session, providing a facility for the implementation 64 * to interact with the user in the voice interaction layer. The user interface is 65 * initially shown by default, and can be created be overriding {@link #onCreateContentView()} 66 * in which the UI can be built. 67 * 68 * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish} 69 * when done. It can also initiate voice interactions with applications by calling 70 * {@link #startVoiceActivity}</p>. 71 */ 72public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 { 73 static final String TAG = "VoiceInteractionSession"; 74 static final boolean DEBUG = false; 75 76 /** 77 * Flag received in {@link #onShow}: originator requested that the session be started with 78 * assist data from the currently focused activity. 79 */ 80 public static final int SHOW_WITH_ASSIST = 1<<0; 81 82 /** 83 * Flag received in {@link #onShow}: originator requested that the session be started with 84 * a screen shot of the currently focused activity. 85 */ 86 public static final int SHOW_WITH_SCREENSHOT = 1<<1; 87 88 /** 89 * Flag for use with {@link #onShow}: indicates that the session has been started from the 90 * system assist gesture. 91 */ 92 public static final int SHOW_SOURCE_ASSIST_GESTURE = 1<<2; 93 94 /** 95 * Flag for use with {@link #onShow}: indicates that the application itself has invoked 96 * the assistant. 97 */ 98 public static final int SHOW_SOURCE_APPLICATION = 1<<3; 99 100 final Context mContext; 101 final HandlerCaller mHandlerCaller; 102 103 final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); 104 105 IVoiceInteractionManagerService mSystemService; 106 IBinder mToken; 107 108 int mTheme = 0; 109 LayoutInflater mInflater; 110 TypedArray mThemeAttrs; 111 View mRootView; 112 FrameLayout mContentFrame; 113 SoftInputWindow mWindow; 114 115 boolean mInitialized; 116 boolean mWindowAdded; 117 boolean mWindowVisible; 118 boolean mWindowWasVisible; 119 boolean mInShowWindow; 120 121 final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); 122 123 final Insets mTmpInsets = new Insets(); 124 125 final WeakReference<VoiceInteractionSession> mWeakRef 126 = new WeakReference<VoiceInteractionSession>(this); 127 128 final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { 129 @Override 130 public IVoiceInteractorRequest startConfirmation(String callingPackage, 131 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, Bundle extras) { 132 ConfirmationRequest request = new ConfirmationRequest(callingPackage, 133 Binder.getCallingUid(), callback, VoiceInteractionSession.this, 134 prompt, extras); 135 addRequest(request); 136 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_CONFIRMATION, 137 request)); 138 return request.mInterface; 139 } 140 141 @Override 142 public IVoiceInteractorRequest startPickOption(String callingPackage, 143 IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, 144 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { 145 PickOptionRequest request = new PickOptionRequest(callingPackage, 146 Binder.getCallingUid(), callback, VoiceInteractionSession.this, 147 prompt, options, extras); 148 addRequest(request); 149 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_PICK_OPTION, 150 request)); 151 return request.mInterface; 152 } 153 154 @Override 155 public IVoiceInteractorRequest startCompleteVoice(String callingPackage, 156 IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) { 157 CompleteVoiceRequest request = new CompleteVoiceRequest(callingPackage, 158 Binder.getCallingUid(), callback, VoiceInteractionSession.this, 159 message, extras); 160 addRequest(request); 161 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMPLETE_VOICE, 162 request)); 163 return request.mInterface; 164 } 165 166 @Override 167 public IVoiceInteractorRequest startAbortVoice(String callingPackage, 168 IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) { 169 AbortVoiceRequest request = new AbortVoiceRequest(callingPackage, 170 Binder.getCallingUid(), callback, VoiceInteractionSession.this, 171 message, extras); 172 addRequest(request); 173 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_ABORT_VOICE, 174 request)); 175 return request.mInterface; 176 } 177 178 @Override 179 public IVoiceInteractorRequest startCommand(String callingPackage, 180 IVoiceInteractorCallback callback, String command, Bundle extras) { 181 CommandRequest request = new CommandRequest(callingPackage, 182 Binder.getCallingUid(), callback, VoiceInteractionSession.this, 183 command, extras); 184 addRequest(request); 185 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_START_COMMAND, 186 request)); 187 return request.mInterface; 188 } 189 190 @Override 191 public boolean[] supportsCommands(String callingPackage, String[] commands) { 192 Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS, 193 0, commands, null); 194 SomeArgs args = mHandlerCaller.sendMessageAndWait(msg); 195 if (args != null) { 196 boolean[] res = (boolean[])args.arg1; 197 args.recycle(); 198 return res; 199 } 200 return new boolean[commands.length]; 201 } 202 }; 203 204 final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() { 205 @Override 206 public void show(Bundle sessionArgs, int flags, 207 IVoiceInteractionSessionShowCallback showCallback) { 208 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_SHOW, 209 flags, sessionArgs, showCallback)); 210 } 211 212 @Override 213 public void hide() { 214 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE)); 215 } 216 217 @Override 218 public void handleAssist(final Bundle data, final AssistStructure structure, 219 final AssistContent content) { 220 // We want to pre-warm the AssistStructure before handing it off to the main 221 // thread. We also want to do this on a separate thread, so that if the app 222 // is for some reason slow (due to slow filling in of async children in the 223 // structure), we don't block other incoming IPCs (such as the screenshot) to 224 // us (since we are a oneway interface, they get serialized). (Okay?) 225 Thread retriever = new Thread("AssistStructure retriever") { 226 @Override 227 public void run() { 228 Throwable failure = null; 229 if (structure != null) { 230 try { 231 structure.ensureData(); 232 } catch (Throwable e) { 233 Log.w(TAG, "Failure retrieving AssistStructure", e); 234 failure = e; 235 } 236 } 237 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_HANDLE_ASSIST, 238 data, failure == null ? structure : null, failure, content)); 239 } 240 }; 241 retriever.start(); 242 } 243 244 @Override 245 public void handleScreenshot(Bitmap screenshot) { 246 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_SCREENSHOT, 247 screenshot)); 248 } 249 250 @Override 251 public void taskStarted(Intent intent, int taskId) { 252 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED, 253 taskId, intent)); 254 } 255 256 @Override 257 public void taskFinished(Intent intent, int taskId) { 258 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED, 259 taskId, intent)); 260 } 261 262 @Override 263 public void closeSystemDialogs() { 264 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS)); 265 } 266 267 @Override 268 public void destroy() { 269 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY)); 270 } 271 }; 272 273 /** 274 * Base class representing a request from a voice-driver app to perform a particular 275 * voice operation with the user. See related subclasses for the types of requests 276 * that are possible. 277 */ 278 public static class Request { 279 final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() { 280 @Override 281 public void cancel() throws RemoteException { 282 VoiceInteractionSession session = mSession.get(); 283 if (session != null) { 284 session.mHandlerCaller.sendMessage( 285 session.mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this)); 286 } 287 } 288 }; 289 final String mCallingPackage; 290 final int mCallingUid; 291 final IVoiceInteractorCallback mCallback; 292 final WeakReference<VoiceInteractionSession> mSession; 293 final Bundle mExtras; 294 295 Request(String packageName, int uid, IVoiceInteractorCallback callback, 296 VoiceInteractionSession session, Bundle extras) { 297 mCallingPackage = packageName; 298 mCallingUid = uid; 299 mCallback = callback; 300 mSession = session.mWeakRef; 301 mExtras = extras; 302 } 303 304 /** 305 * Return the uid of the application that initiated the request. 306 */ 307 public int getCallingUid() { 308 return mCallingUid; 309 } 310 311 /** 312 * Return the package name of the application that initiated the request. 313 */ 314 public String getCallingPackage() { 315 return mCallingPackage; 316 } 317 318 /** 319 * Return any additional extra information that was supplied as part of the request. 320 */ 321 public Bundle getExtras() { 322 return mExtras; 323 } 324 325 void finishRequest() { 326 VoiceInteractionSession session = mSession.get(); 327 if (session == null) { 328 throw new IllegalStateException("VoiceInteractionSession has been destroyed"); 329 } 330 Request req = session.removeRequest(mInterface.asBinder()); 331 if (req == null) { 332 throw new IllegalStateException("Request not active: " + this); 333 } else if (req != this) { 334 throw new IllegalStateException("Current active request " + req 335 + " not same as calling request " + this); 336 } 337 } 338 339 /** 340 * Ask the app to cancel this current request. 341 */ 342 public void cancel() { 343 try { 344 if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface); 345 finishRequest(); 346 mCallback.deliverCancel(mInterface); 347 } catch (RemoteException e) { 348 } 349 } 350 } 351 352 /** 353 * A request for confirmation from the user of an operation, as per 354 * {@link android.app.VoiceInteractor.ConfirmationRequest 355 * VoiceInteractor.ConfirmationRequest}. 356 */ 357 public static final class ConfirmationRequest extends Request { 358 final VoiceInteractor.Prompt mPrompt; 359 360 ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback, 361 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { 362 super(packageName, uid, callback, session, extras); 363 mPrompt = prompt; 364 } 365 366 /** 367 * Return the prompt informing the user of what will happen, as per 368 * {@link android.app.VoiceInteractor.ConfirmationRequest 369 * VoiceInteractor.ConfirmationRequest}. 370 */ 371 @Nullable 372 public VoiceInteractor.Prompt getVoicePrompt() { 373 return mPrompt; 374 } 375 376 /** 377 * Return the prompt informing the user of what will happen, as per 378 * {@link android.app.VoiceInteractor.ConfirmationRequest 379 * VoiceInteractor.ConfirmationRequest}. 380 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts. 381 */ 382 @Nullable 383 public CharSequence getPrompt() { 384 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); 385 } 386 387 /** 388 * Report that the voice interactor has confirmed the operation with the user, resulting 389 * in a call to 390 * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult 391 * VoiceInteractor.ConfirmationRequest.onConfirmationResult}. 392 */ 393 public void sendConfirmationResult(boolean confirmed, Bundle result) { 394 try { 395 if (DEBUG) Log.d(TAG, "sendConfirmationResult: req=" + mInterface 396 + " confirmed=" + confirmed + " result=" + result); 397 finishRequest(); 398 mCallback.deliverConfirmationResult(mInterface, confirmed, result); 399 } catch (RemoteException e) { 400 } 401 } 402 } 403 404 /** 405 * A request for the user to pick from a set of option, as per 406 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. 407 */ 408 public static final class PickOptionRequest extends Request { 409 final VoiceInteractor.Prompt mPrompt; 410 final VoiceInteractor.PickOptionRequest.Option[] mOptions; 411 412 PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback, 413 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, 414 VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { 415 super(packageName, uid, callback, session, extras); 416 mPrompt = prompt; 417 mOptions = options; 418 } 419 420 /** 421 * Return the prompt informing the user of what they are picking, as per 422 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. 423 */ 424 @Nullable 425 public VoiceInteractor.Prompt getVoicePrompt() { 426 return mPrompt; 427 } 428 429 /** 430 * Return the prompt informing the user of what they are picking, as per 431 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. 432 * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts. 433 */ 434 @Nullable 435 public CharSequence getPrompt() { 436 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); 437 } 438 439 /** 440 * Return the set of options the user is picking from, as per 441 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. 442 */ 443 public VoiceInteractor.PickOptionRequest.Option[] getOptions() { 444 return mOptions; 445 } 446 447 void sendPickOptionResult(boolean finished, 448 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { 449 try { 450 if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface 451 + " finished=" + finished + " selections=" + selections 452 + " result=" + result); 453 if (finished) { 454 finishRequest(); 455 } 456 mCallback.deliverPickOptionResult(mInterface, finished, selections, result); 457 } catch (RemoteException e) { 458 } 459 } 460 461 /** 462 * Report an intermediate option selection from the request, without completing it (the 463 * request is still active and the app is waiting for the final option selection), 464 * resulting in a call to 465 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult 466 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished. 467 */ 468 public void sendIntermediatePickOptionResult( 469 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { 470 sendPickOptionResult(false, selections, result); 471 } 472 473 /** 474 * Report the final option selection for the request, completing the request 475 * and resulting in a call to 476 * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult 477 * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished. 478 */ 479 public void sendPickOptionResult( 480 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) { 481 sendPickOptionResult(true, selections, result); 482 } 483 } 484 485 /** 486 * A request to simply inform the user that the voice operation has completed, as per 487 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 488 * VoiceInteractor.CompleteVoiceRequest}. 489 */ 490 public static final class CompleteVoiceRequest extends Request { 491 final VoiceInteractor.Prompt mPrompt; 492 493 CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, 494 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { 495 super(packageName, uid, callback, session, extras); 496 mPrompt = prompt; 497 } 498 499 /** 500 * Return the message informing the user of the completion, as per 501 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 502 * VoiceInteractor.CompleteVoiceRequest}. 503 */ 504 @Nullable 505 public VoiceInteractor.Prompt getVoicePrompt() { 506 return mPrompt; 507 } 508 509 /** 510 * Return the message informing the user of the completion, as per 511 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 512 * VoiceInteractor.CompleteVoiceRequest}. 513 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message. 514 */ 515 @Nullable 516 public CharSequence getMessage() { 517 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); 518 } 519 520 /** 521 * Report that the voice interactor has finished completing the voice operation, resulting 522 * in a call to 523 * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult 524 * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}. 525 */ 526 public void sendCompleteResult(Bundle result) { 527 try { 528 if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface 529 + " result=" + result); 530 finishRequest(); 531 mCallback.deliverCompleteVoiceResult(mInterface, result); 532 } catch (RemoteException e) { 533 } 534 } 535 } 536 537 /** 538 * A request to report that the current user interaction can not be completed with voice, as per 539 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. 540 */ 541 public static final class AbortVoiceRequest extends Request { 542 final VoiceInteractor.Prompt mPrompt; 543 544 AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, 545 VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { 546 super(packageName, uid, callback, session, extras); 547 mPrompt = prompt; 548 } 549 550 /** 551 * Return the message informing the user of the problem, as per 552 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. 553 */ 554 @Nullable 555 public VoiceInteractor.Prompt getVoicePrompt() { 556 return mPrompt; 557 } 558 559 /** 560 * Return the message informing the user of the problem, as per 561 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. 562 * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message. 563 */ 564 @Nullable 565 public CharSequence getMessage() { 566 return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); 567 } 568 569 /** 570 * Report that the voice interactor has finished aborting the voice operation, resulting 571 * in a call to 572 * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult 573 * VoiceInteractor.AbortVoiceRequest.onAbortResult}. 574 */ 575 public void sendAbortResult(Bundle result) { 576 try { 577 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface 578 + " result=" + result); 579 finishRequest(); 580 mCallback.deliverAbortVoiceResult(mInterface, result); 581 } catch (RemoteException e) { 582 } 583 } 584 } 585 586 /** 587 * A generic vendor-specific request, as per 588 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. 589 */ 590 public static final class CommandRequest extends Request { 591 final String mCommand; 592 593 CommandRequest(String packageName, int uid, IVoiceInteractorCallback callback, 594 VoiceInteractionSession session, String command, Bundle extras) { 595 super(packageName, uid, callback, session, extras); 596 mCommand = command; 597 } 598 599 /** 600 * Return the command that is being executed, as per 601 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. 602 */ 603 public String getCommand() { 604 return mCommand; 605 } 606 607 void sendCommandResult(boolean finished, Bundle result) { 608 try { 609 if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface 610 + " result=" + result); 611 if (finished) { 612 finishRequest(); 613 } 614 mCallback.deliverCommandResult(mInterface, finished, result); 615 } catch (RemoteException e) { 616 } 617 } 618 619 /** 620 * Report an intermediate result of the request, without completing it (the request 621 * is still active and the app is waiting for the final result), resulting in a call to 622 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult 623 * VoiceInteractor.CommandRequest.onCommandResult} with false for isCompleted. 624 */ 625 public void sendIntermediateResult(Bundle result) { 626 sendCommandResult(false, result); 627 } 628 629 /** 630 * Report the final result of the request, completing the request and resulting in a call to 631 * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult 632 * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted. 633 */ 634 public void sendResult(Bundle result) { 635 sendCommandResult(true, result); 636 } 637 } 638 639 static final int MSG_START_CONFIRMATION = 1; 640 static final int MSG_START_PICK_OPTION = 2; 641 static final int MSG_START_COMPLETE_VOICE = 3; 642 static final int MSG_START_ABORT_VOICE = 4; 643 static final int MSG_START_COMMAND = 5; 644 static final int MSG_SUPPORTS_COMMANDS = 6; 645 static final int MSG_CANCEL = 7; 646 647 static final int MSG_TASK_STARTED = 100; 648 static final int MSG_TASK_FINISHED = 101; 649 static final int MSG_CLOSE_SYSTEM_DIALOGS = 102; 650 static final int MSG_DESTROY = 103; 651 static final int MSG_HANDLE_ASSIST = 104; 652 static final int MSG_HANDLE_SCREENSHOT = 105; 653 static final int MSG_SHOW = 106; 654 static final int MSG_HIDE = 107; 655 656 class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { 657 @Override 658 public void executeMessage(Message msg) { 659 SomeArgs args = null; 660 switch (msg.what) { 661 case MSG_START_CONFIRMATION: 662 if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj); 663 onRequestConfirmation((ConfirmationRequest) msg.obj); 664 break; 665 case MSG_START_PICK_OPTION: 666 if (DEBUG) Log.d(TAG, "onPickOption: req=" + msg.obj); 667 onRequestPickOption((PickOptionRequest) msg.obj); 668 break; 669 case MSG_START_COMPLETE_VOICE: 670 if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + msg.obj); 671 onRequestCompleteVoice((CompleteVoiceRequest) msg.obj); 672 break; 673 case MSG_START_ABORT_VOICE: 674 if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + msg.obj); 675 onRequestAbortVoice((AbortVoiceRequest) msg.obj); 676 break; 677 case MSG_START_COMMAND: 678 if (DEBUG) Log.d(TAG, "onCommand: req=" + msg.obj); 679 onRequestCommand((CommandRequest) msg.obj); 680 break; 681 case MSG_SUPPORTS_COMMANDS: 682 args = (SomeArgs)msg.obj; 683 if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1); 684 args.arg1 = onGetSupportedCommands((String[]) args.arg1); 685 args.complete(); 686 args = null; 687 break; 688 case MSG_CANCEL: 689 if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj)); 690 onCancelRequest((Request) msg.obj); 691 break; 692 case MSG_TASK_STARTED: 693 if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj 694 + " taskId=" + msg.arg1); 695 onTaskStarted((Intent) msg.obj, msg.arg1); 696 break; 697 case MSG_TASK_FINISHED: 698 if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj 699 + " taskId=" + msg.arg1); 700 onTaskFinished((Intent) msg.obj, msg.arg1); 701 break; 702 case MSG_CLOSE_SYSTEM_DIALOGS: 703 if (DEBUG) Log.d(TAG, "onCloseSystemDialogs"); 704 onCloseSystemDialogs(); 705 break; 706 case MSG_DESTROY: 707 if (DEBUG) Log.d(TAG, "doDestroy"); 708 doDestroy(); 709 break; 710 case MSG_HANDLE_ASSIST: 711 args = (SomeArgs)msg.obj; 712 if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1 713 + " structure=" + args.arg2 + " content=" + args.arg3); 714 doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2, 715 (Throwable) args.arg3, (AssistContent) args.arg4); 716 break; 717 case MSG_HANDLE_SCREENSHOT: 718 if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj); 719 onHandleScreenshot((Bitmap) msg.obj); 720 break; 721 case MSG_SHOW: 722 args = (SomeArgs)msg.obj; 723 if (DEBUG) Log.d(TAG, "doShow: args=" + args.arg1 724 + " flags=" + msg.arg1 725 + " showCallback=" + args.arg2); 726 doShow((Bundle) args.arg1, msg.arg1, 727 (IVoiceInteractionSessionShowCallback) args.arg2); 728 break; 729 case MSG_HIDE: 730 if (DEBUG) Log.d(TAG, "doHide"); 731 doHide(); 732 break; 733 } 734 if (args != null) { 735 args.recycle(); 736 } 737 } 738 739 @Override 740 public void onBackPressed() { 741 VoiceInteractionSession.this.onBackPressed(); 742 } 743 } 744 745 final MyCallbacks mCallbacks = new MyCallbacks(); 746 747 /** 748 * Information about where interesting parts of the input method UI appear. 749 */ 750 public static final class Insets { 751 /** 752 * This is the part of the UI that is the main content. It is 753 * used to determine the basic space needed, to resize/pan the 754 * application behind. It is assumed that this inset does not 755 * change very much, since any change will cause a full resize/pan 756 * of the application behind. This value is relative to the top edge 757 * of the input method window. 758 */ 759 public final Rect contentInsets = new Rect(); 760 761 /** 762 * This is the region of the UI that is touchable. It is used when 763 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}. 764 * The region should be specified relative to the origin of the window frame. 765 */ 766 public final Region touchableRegion = new Region(); 767 768 /** 769 * Option for {@link #touchableInsets}: the entire window frame 770 * can be touched. 771 */ 772 public static final int TOUCHABLE_INSETS_FRAME 773 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; 774 775 /** 776 * Option for {@link #touchableInsets}: the area inside of 777 * the content insets can be touched. 778 */ 779 public static final int TOUCHABLE_INSETS_CONTENT 780 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; 781 782 /** 783 * Option for {@link #touchableInsets}: the region specified by 784 * {@link #touchableRegion} can be touched. 785 */ 786 public static final int TOUCHABLE_INSETS_REGION 787 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 788 789 /** 790 * Determine which area of the window is touchable by the user. May 791 * be one of: {@link #TOUCHABLE_INSETS_FRAME}, 792 * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}. 793 */ 794 public int touchableInsets; 795 } 796 797 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = 798 new ViewTreeObserver.OnComputeInternalInsetsListener() { 799 public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { 800 onComputeInsets(mTmpInsets); 801 info.contentInsets.set(mTmpInsets.contentInsets); 802 info.visibleInsets.set(mTmpInsets.contentInsets); 803 info.touchableRegion.set(mTmpInsets.touchableRegion); 804 info.setTouchableInsets(mTmpInsets.touchableInsets); 805 } 806 }; 807 808 public VoiceInteractionSession(Context context) { 809 this(context, new Handler()); 810 } 811 812 public VoiceInteractionSession(Context context, Handler handler) { 813 mContext = context; 814 mHandlerCaller = new HandlerCaller(context, handler.getLooper(), 815 mCallbacks, true); 816 } 817 818 public Context getContext() { 819 return mContext; 820 } 821 822 void addRequest(Request req) { 823 mActiveRequests.put(req.mInterface.asBinder(), req); 824 } 825 826 Request removeRequest(IBinder reqInterface) { 827 synchronized (this) { 828 return mActiveRequests.remove(reqInterface); 829 } 830 } 831 832 void doCreate(IVoiceInteractionManagerService service, IBinder token) { 833 mSystemService = service; 834 mToken = token; 835 onCreate(); 836 } 837 838 void doShow(Bundle args, int flags, final IVoiceInteractionSessionShowCallback showCallback) { 839 if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded 840 + " mWindowVisible=" + mWindowVisible); 841 842 if (mInShowWindow) { 843 Log.w(TAG, "Re-entrance in to showWindow"); 844 return; 845 } 846 847 try { 848 mInShowWindow = true; 849 if (!mWindowVisible) { 850 if (!mWindowAdded) { 851 mWindowAdded = true; 852 View v = onCreateContentView(); 853 if (v != null) { 854 setContentView(v); 855 } 856 } 857 } 858 onShow(args, flags); 859 if (!mWindowVisible) { 860 mWindowVisible = true; 861 mWindow.show(); 862 } 863 if (showCallback != null) { 864 mRootView.invalidate(); 865 mRootView.getViewTreeObserver().addOnPreDrawListener( 866 new ViewTreeObserver.OnPreDrawListener() { 867 @Override 868 public boolean onPreDraw() { 869 mRootView.getViewTreeObserver().removeOnPreDrawListener(this); 870 try { 871 showCallback.onShown(); 872 } catch (RemoteException e) { 873 Log.w(TAG, "Error calling onShown", e); 874 } 875 return true; 876 } 877 }); 878 } 879 } finally { 880 mWindowWasVisible = true; 881 mInShowWindow = false; 882 } 883 } 884 885 void doHide() { 886 if (mWindowVisible) { 887 mWindow.hide(); 888 mWindowVisible = false; 889 onHide(); 890 } 891 } 892 893 void doDestroy() { 894 onDestroy(); 895 if (mInitialized) { 896 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener( 897 mInsetsComputer); 898 if (mWindowAdded) { 899 mWindow.dismiss(); 900 mWindowAdded = false; 901 } 902 mInitialized = false; 903 } 904 } 905 906 void initViews() { 907 mInitialized = true; 908 909 mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession); 910 mRootView = mInflater.inflate( 911 com.android.internal.R.layout.voice_interaction_session, null); 912 mRootView.setSystemUiVisibility( 913 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 914 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 915 mWindow.setContentView(mRootView); 916 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer); 917 918 mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content); 919 } 920 921 /** 922 * Equivalent to {@link VoiceInteractionService#setDisabledShowContext 923 * VoiceInteractionService.setDisabledShowContext(int)}. 924 */ 925 public void setDisabledShowContext(int flags) { 926 try { 927 mSystemService.setDisabledShowContext(flags); 928 } catch (RemoteException e) { 929 } 930 } 931 932 /** 933 * Equivalent to {@link VoiceInteractionService#getDisabledShowContext 934 * VoiceInteractionService.getDisabledShowContext}. 935 */ 936 public int getDisabledShowContext() { 937 try { 938 return mSystemService.getDisabledShowContext(); 939 } catch (RemoteException e) { 940 return 0; 941 } 942 } 943 944 /** 945 * Return which show context flags have been disabled by the user through the system 946 * settings UI, so the session will never get this data. Returned flags are any combination of 947 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and 948 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT 949 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. Note that this only tells you about 950 * global user settings, not about restrictions that may be applied contextual based on 951 * the current application the user is in or other transient states. 952 */ 953 public int getUserDisabledShowContext() { 954 try { 955 return mSystemService.getUserDisabledShowContext(); 956 } catch (RemoteException e) { 957 return 0; 958 } 959 } 960 961 /** 962 * Show the UI for this session. This asks the system to go through the process of showing 963 * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling 964 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. 965 * @param args Arbitrary arguments that will be propagated {@link #onShow}. 966 * @param flags Indicates additional optional behavior that should be performed. May 967 * be any combination of 968 * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and 969 * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT 970 * VoiceInteractionSession.SHOW_WITH_SCREENSHOT} 971 * to request that the system generate and deliver assist data on the current foreground 972 * app as part of showing the session UI. 973 */ 974 public void show(Bundle args, int flags) { 975 if (mToken == null) { 976 throw new IllegalStateException("Can't call before onCreate()"); 977 } 978 try { 979 mSystemService.showSessionFromSession(mToken, args, flags); 980 } catch (RemoteException e) { 981 } 982 } 983 984 /** 985 * Hide the session's UI, if currently shown. Call this when you are done with your 986 * user interaction. 987 */ 988 public void hide() { 989 if (mToken == null) { 990 throw new IllegalStateException("Can't call before onCreate()"); 991 } 992 try { 993 mSystemService.hideSessionFromSession(mToken); 994 } catch (RemoteException e) { 995 } 996 } 997 998 /** 999 * You can call this to customize the theme used by your IME's window. 1000 * This must be set before {@link #onCreate}, so you 1001 * will typically call it in your constructor with the resource ID 1002 * of your custom theme. 1003 */ 1004 public void setTheme(int theme) { 1005 if (mWindow != null) { 1006 throw new IllegalStateException("Must be called before onCreate()"); 1007 } 1008 mTheme = theme; 1009 } 1010 1011 /** 1012 * Ask that a new activity be started for voice interaction. This will create a 1013 * new dedicated task in the activity manager for this voice interaction session; 1014 * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK} 1015 * will be set for you to make it a new task. 1016 * 1017 * <p>The newly started activity will be displayed to the user in a special way, as 1018 * a layer under the voice interaction UI.</p> 1019 * 1020 * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor} 1021 * through which it can perform voice interactions through your session. These requests 1022 * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands}, 1023 * {@link #onRequestConfirmation}, {@link #onRequestPickOption}, 1024 * {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice}, 1025 * or {@link #onRequestCommand} 1026 * 1027 * <p>You will receive a call to {@link #onTaskStarted} when the task starts up 1028 * and {@link #onTaskFinished} when the last activity has finished. 1029 * 1030 * @param intent The Intent to start this voice interaction. The given Intent will 1031 * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since 1032 * this is part of a voice interaction. 1033 */ 1034 public void startVoiceActivity(Intent intent) { 1035 if (mToken == null) { 1036 throw new IllegalStateException("Can't call before onCreate()"); 1037 } 1038 try { 1039 intent.migrateExtraStreamToClipData(); 1040 intent.prepareToLeaveProcess(); 1041 int res = mSystemService.startVoiceActivity(mToken, intent, 1042 intent.resolveType(mContext.getContentResolver())); 1043 Instrumentation.checkStartActivityResult(res, intent); 1044 } catch (RemoteException e) { 1045 } 1046 } 1047 1048 /** 1049 * Set whether this session will keep the device awake while it is running a voice 1050 * activity. By default, the system holds a wake lock for it while in this state, 1051 * so that it can work even if the screen is off. Setting this to false removes that 1052 * wake lock, allowing the CPU to go to sleep. This is typically used if the 1053 * session decides it has been waiting too long for a response from the user and 1054 * doesn't want to let this continue to drain the battery. 1055 * 1056 * <p>Passing false here will release the wake lock, and you can call later with 1057 * true to re-acquire it. It will also be automatically re-acquired for you each 1058 * time you start a new voice activity task -- that is when you call 1059 * {@link #startVoiceActivity}.</p> 1060 */ 1061 public void setKeepAwake(boolean keepAwake) { 1062 if (mToken == null) { 1063 throw new IllegalStateException("Can't call before onCreate()"); 1064 } 1065 try { 1066 mSystemService.setKeepAwake(mToken, keepAwake); 1067 } catch (RemoteException e) { 1068 } 1069 } 1070 1071 /** 1072 * Request that all system dialogs (and status bar shade etc) be closed, allowing 1073 * access to the session's UI. This will <em>not</em> cause the lock screen to be 1074 * dismissed. 1075 */ 1076 public void closeSystemDialogs() { 1077 if (mToken == null) { 1078 throw new IllegalStateException("Can't call before onCreate()"); 1079 } 1080 try { 1081 mSystemService.closeSystemDialogs(mToken); 1082 } catch (RemoteException e) { 1083 } 1084 } 1085 1086 /** 1087 * Convenience for inflating views. 1088 */ 1089 public LayoutInflater getLayoutInflater() { 1090 return mInflater; 1091 } 1092 1093 /** 1094 * Retrieve the window being used to show the session's UI. 1095 */ 1096 public Dialog getWindow() { 1097 return mWindow; 1098 } 1099 1100 /** 1101 * Finish the session. This completely destroys the session -- the next time it is shown, 1102 * an entirely new one will be created. You do not normally call this function; instead, 1103 * use {@link #hide} and allow the system to destroy your session if it needs its RAM. 1104 */ 1105 public void finish() { 1106 if (mToken == null) { 1107 throw new IllegalStateException("Can't call before onCreate()"); 1108 } 1109 try { 1110 mSystemService.finish(mToken); 1111 } catch (RemoteException e) { 1112 } 1113 } 1114 1115 /** 1116 * Initiatize a new session. At this point you don't know exactly what this 1117 * session will be used for; you will find that out in {@link #onShow}. 1118 */ 1119 public void onCreate() { 1120 doOnCreate(); 1121 } 1122 1123 private void doOnCreate() { 1124 mTheme = mTheme != 0 ? mTheme 1125 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession; 1126 mInflater = (LayoutInflater)mContext.getSystemService( 1127 Context.LAYOUT_INFLATER_SERVICE); 1128 mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme, 1129 mCallbacks, this, mDispatcherState, 1130 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true); 1131 mWindow.getWindow().addFlags( 1132 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | 1133 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | 1134 WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); 1135 initViews(); 1136 mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT); 1137 mWindow.setToken(mToken); 1138 } 1139 1140 /** 1141 * Called when the session UI is going to be shown. This is called after 1142 * {@link #onCreateContentView} (if the session's content UI needed to be created) and 1143 * immediately prior to the window being shown. This may be called while the window 1144 * is already shown, if a show request has come in while it is shown, to allow you to 1145 * update the UI to match the new show arguments. 1146 * 1147 * @param args The arguments that were supplied to 1148 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. 1149 * @param showFlags The show flags originally provided to 1150 * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. 1151 */ 1152 public void onShow(Bundle args, int showFlags) { 1153 } 1154 1155 /** 1156 * Called immediately after stopping to show the session UI. 1157 */ 1158 public void onHide() { 1159 } 1160 1161 /** 1162 * Last callback to the session as it is being finished. 1163 */ 1164 public void onDestroy() { 1165 } 1166 1167 /** 1168 * Hook in which to create the session's UI. 1169 */ 1170 public View onCreateContentView() { 1171 return null; 1172 } 1173 1174 public void setContentView(View view) { 1175 mContentFrame.removeAllViews(); 1176 mContentFrame.addView(view, new FrameLayout.LayoutParams( 1177 ViewGroup.LayoutParams.MATCH_PARENT, 1178 ViewGroup.LayoutParams.MATCH_PARENT)); 1179 mContentFrame.requestApplyInsets(); 1180 } 1181 1182 void doOnHandleAssist(Bundle data, AssistStructure structure, Throwable failure, 1183 AssistContent content) { 1184 if (failure != null) { 1185 onAssistStructureFailure(failure); 1186 } 1187 onHandleAssist(data, structure, content); 1188 } 1189 1190 /** 1191 * Called when there has been a failure transferring the {@link AssistStructure} to 1192 * the assistant. This may happen, for example, if the data is too large and results 1193 * in an out of memory exception, or the client has provided corrupt data. This will 1194 * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied 1195 * there afterwards will be null. 1196 * 1197 * @param failure The failure exception that was thrown when building the 1198 * {@link AssistStructure}. 1199 */ 1200 public void onAssistStructureFailure(Throwable failure) { 1201 } 1202 1203 /** 1204 * Called to receive data from the application that the user was currently viewing when 1205 * an assist session is started. If the original show request did not specify 1206 * {@link #SHOW_WITH_ASSIST}, this method will not be called. 1207 * 1208 * @param data Arbitrary data supplied by the app through 1209 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 1210 * May be null if assist data has been disabled by the user or device policy. 1211 * @param structure If available, the structure definition of all windows currently 1212 * displayed by the app. May be null if assist data has been disabled by the user 1213 * or device policy; will be an empty stub if the application has disabled assist 1214 * by marking its window as secure. 1215 * @param content Additional content data supplied by the app through 1216 * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. 1217 * May be null if assist data has been disabled by the user or device policy; will 1218 * not be automatically filled in with data from the app if the app has marked its 1219 * window as secure. 1220 */ 1221 public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure, 1222 @Nullable AssistContent content) { 1223 } 1224 1225 /** 1226 * Called to receive a screenshot of what the user was currently viewing when an assist 1227 * session is started. May be null if screenshots are disabled by the user, policy, 1228 * or application. If the original show request did not specify 1229 * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called. 1230 */ 1231 public void onHandleScreenshot(@Nullable Bitmap screenshot) { 1232 } 1233 1234 public boolean onKeyDown(int keyCode, KeyEvent event) { 1235 return false; 1236 } 1237 1238 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 1239 return false; 1240 } 1241 1242 public boolean onKeyUp(int keyCode, KeyEvent event) { 1243 return false; 1244 } 1245 1246 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 1247 return false; 1248 } 1249 1250 /** 1251 * Called when the user presses the back button while focus is in the session UI. Note 1252 * that this will only happen if the session UI has requested input focus in its window; 1253 * otherwise, the back key will go to whatever window has focus and do whatever behavior 1254 * it normally has there. The default implementation simply calls {@link #hide}. 1255 */ 1256 public void onBackPressed() { 1257 hide(); 1258 } 1259 1260 /** 1261 * Sessions automatically watch for requests that all system UI be closed (such as when 1262 * the user presses HOME), which will appear here. The default implementation always 1263 * calls {@link #hide}. 1264 */ 1265 public void onCloseSystemDialogs() { 1266 hide(); 1267 } 1268 1269 @Override 1270 public void onConfigurationChanged(Configuration newConfig) { 1271 } 1272 1273 @Override 1274 public void onLowMemory() { 1275 } 1276 1277 @Override 1278 public void onTrimMemory(int level) { 1279 } 1280 1281 /** 1282 * Compute the interesting insets into your UI. The default implementation 1283 * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height 1284 * of the window, meaning it should not adjust content underneath. The default touchable 1285 * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch 1286 * events within its window frame. 1287 * 1288 * @param outInsets Fill in with the current UI insets. 1289 */ 1290 public void onComputeInsets(Insets outInsets) { 1291 outInsets.contentInsets.left = 0; 1292 outInsets.contentInsets.bottom = 0; 1293 outInsets.contentInsets.right = 0; 1294 View decor = getWindow().getWindow().getDecorView(); 1295 outInsets.contentInsets.top = decor.getHeight(); 1296 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME; 1297 outInsets.touchableRegion.setEmpty(); 1298 } 1299 1300 /** 1301 * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)} 1302 * has actually started. 1303 * 1304 * @param intent The original {@link Intent} supplied to 1305 * {@link #startVoiceActivity(android.content.Intent)}. 1306 * @param taskId Unique ID of the now running task. 1307 */ 1308 public void onTaskStarted(Intent intent, int taskId) { 1309 } 1310 1311 /** 1312 * Called when the last activity of a task initiated by 1313 * {@link #startVoiceActivity(android.content.Intent)} has finished. The default 1314 * implementation calls {@link #finish()} on the assumption that this represents 1315 * the completion of a voice action. You can override the implementation if you would 1316 * like a different behavior. 1317 * 1318 * @param intent The original {@link Intent} supplied to 1319 * {@link #startVoiceActivity(android.content.Intent)}. 1320 * @param taskId Unique ID of the finished task. 1321 */ 1322 public void onTaskFinished(Intent intent, int taskId) { 1323 hide(); 1324 } 1325 1326 /** 1327 * Request to query for what extended commands the session supports. 1328 * 1329 * @param commands An array of commands that are being queried. 1330 * @return Return an array of booleans indicating which of each entry in the 1331 * command array is supported. A true entry in the array indicates the command 1332 * is supported; false indicates it is not. The default implementation returns 1333 * an array of all false entries. 1334 */ 1335 public boolean[] onGetSupportedCommands(String[] commands) { 1336 return new boolean[commands.length]; 1337 } 1338 1339 /** 1340 * Request to confirm with the user before proceeding with an unrecoverable operation, 1341 * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest 1342 * VoiceInteractor.ConfirmationRequest}. 1343 * 1344 * @param request The active request. 1345 */ 1346 public void onRequestConfirmation(ConfirmationRequest request) { 1347 } 1348 1349 /** 1350 * Request for the user to pick one of N options, corresponding to a 1351 * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. 1352 * 1353 * @param request The active request. 1354 */ 1355 public void onRequestPickOption(PickOptionRequest request) { 1356 } 1357 1358 /** 1359 * Request to complete the voice interaction session because the voice activity successfully 1360 * completed its interaction using voice. Corresponds to 1361 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 1362 * VoiceInteractor.CompleteVoiceRequest}. The default implementation just sends an empty 1363 * confirmation back to allow the activity to exit. 1364 * 1365 * @param request The active request. 1366 */ 1367 public void onRequestCompleteVoice(CompleteVoiceRequest request) { 1368 } 1369 1370 /** 1371 * Request to abort the voice interaction session because the voice activity can not 1372 * complete its interaction using voice. Corresponds to 1373 * {@link android.app.VoiceInteractor.AbortVoiceRequest 1374 * VoiceInteractor.AbortVoiceRequest}. The default implementation just sends an empty 1375 * confirmation back to allow the activity to exit. 1376 * 1377 * @param request The active request. 1378 */ 1379 public void onRequestAbortVoice(AbortVoiceRequest request) { 1380 } 1381 1382 /** 1383 * Process an arbitrary extended command from the caller, 1384 * corresponding to a {@link android.app.VoiceInteractor.CommandRequest 1385 * VoiceInteractor.CommandRequest}. 1386 * 1387 * @param request The active request. 1388 */ 1389 public void onRequestCommand(CommandRequest request) { 1390 } 1391 1392 /** 1393 * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request} 1394 * that was previously delivered to {@link #onRequestConfirmation}, 1395 * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice}, 1396 * or {@link #onRequestCommand}. 1397 * 1398 * @param request The request that is being canceled. 1399 */ 1400 public void onCancelRequest(Request request) { 1401 } 1402} 1403