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