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