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