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