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