VoiceInteractionSession.java revision 8ef92bd311e6faf602c9705db663abd451590fff
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.SystemApi; 20import android.app.Dialog; 21import android.app.Instrumentation; 22import android.content.Context; 23import android.content.Intent; 24import android.content.res.TypedArray; 25import android.graphics.Rect; 26import android.graphics.Region; 27import android.inputmethodservice.SoftInputWindow; 28import android.os.Binder; 29import android.os.Bundle; 30import android.os.Handler; 31import android.os.IBinder; 32import android.os.Message; 33import android.os.RemoteException; 34import android.util.ArrayMap; 35import android.util.Log; 36import android.view.Gravity; 37import android.view.KeyEvent; 38import android.view.LayoutInflater; 39import android.view.View; 40import android.view.ViewGroup; 41import android.view.ViewTreeObserver; 42import android.view.WindowManager; 43import android.widget.FrameLayout; 44import com.android.internal.app.IVoiceInteractionManagerService; 45import com.android.internal.app.IVoiceInteractor; 46import com.android.internal.app.IVoiceInteractorCallback; 47import com.android.internal.app.IVoiceInteractorRequest; 48import com.android.internal.os.HandlerCaller; 49import com.android.internal.os.SomeArgs; 50 51import java.lang.ref.WeakReference; 52 53import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 54import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 55 56/** 57 * An active interaction session, started by a {@link VoiceInteractionService}. 58 */ 59public abstract class VoiceInteractionSession implements KeyEvent.Callback { 60 static final String TAG = "VoiceInteractionSession"; 61 static final boolean DEBUG = true; 62 63 final Context mContext; 64 final HandlerCaller mHandlerCaller; 65 66 final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); 67 68 IVoiceInteractionManagerService mSystemService; 69 IBinder mToken; 70 71 int mTheme = 0; 72 LayoutInflater mInflater; 73 TypedArray mThemeAttrs; 74 View mRootView; 75 FrameLayout mContentFrame; 76 SoftInputWindow mWindow; 77 78 boolean mInitialized; 79 boolean mWindowAdded; 80 boolean mWindowVisible; 81 boolean mWindowWasVisible; 82 boolean mInShowWindow; 83 84 final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); 85 86 final Insets mTmpInsets = new Insets(); 87 final int[] mTmpLocation = new int[2]; 88 89 final WeakReference<VoiceInteractionSession> mWeakRef 90 = new WeakReference<VoiceInteractionSession>(this); 91 92 final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { 93 @Override 94 public IVoiceInteractorRequest startConfirmation(String callingPackage, 95 IVoiceInteractorCallback callback, CharSequence prompt, Bundle extras) { 96 Request request = newRequest(callback); 97 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION, 98 new Caller(callingPackage, Binder.getCallingUid()), request, 99 prompt, extras)); 100 return request.mInterface; 101 } 102 103 @Override 104 public IVoiceInteractorRequest startCompleteVoice(String callingPackage, 105 IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { 106 Request request = newRequest(callback); 107 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMPLETE_VOICE, 108 new Caller(callingPackage, Binder.getCallingUid()), request, 109 message, extras)); 110 return request.mInterface; 111 } 112 113 @Override 114 public IVoiceInteractorRequest startAbortVoice(String callingPackage, 115 IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { 116 Request request = newRequest(callback); 117 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_ABORT_VOICE, 118 new Caller(callingPackage, Binder.getCallingUid()), request, 119 message, extras)); 120 return request.mInterface; 121 } 122 123 @Override 124 public IVoiceInteractorRequest startCommand(String callingPackage, 125 IVoiceInteractorCallback callback, String command, Bundle extras) { 126 Request request = newRequest(callback); 127 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND, 128 new Caller(callingPackage, Binder.getCallingUid()), request, 129 command, extras)); 130 return request.mInterface; 131 } 132 133 @Override 134 public boolean[] supportsCommands(String callingPackage, String[] commands) { 135 Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS, 136 0, new Caller(callingPackage, Binder.getCallingUid()), commands); 137 SomeArgs args = mHandlerCaller.sendMessageAndWait(msg); 138 if (args != null) { 139 boolean[] res = (boolean[])args.arg1; 140 args.recycle(); 141 return res; 142 } 143 return new boolean[commands.length]; 144 } 145 }; 146 147 final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() { 148 @Override 149 public void taskStarted(Intent intent, int taskId) { 150 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED, 151 taskId, intent)); 152 } 153 154 @Override 155 public void taskFinished(Intent intent, int taskId) { 156 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED, 157 taskId, intent)); 158 } 159 160 @Override 161 public void closeSystemDialogs() { 162 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS)); 163 } 164 165 @Override 166 public void destroy() { 167 mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY)); 168 } 169 }; 170 171 /** 172 * @hide 173 */ 174 @SystemApi 175 public static class Request { 176 final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() { 177 @Override 178 public void cancel() throws RemoteException { 179 VoiceInteractionSession session = mSession.get(); 180 if (session != null) { 181 session.mHandlerCaller.sendMessage( 182 session.mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this)); 183 } 184 } 185 }; 186 final IVoiceInteractorCallback mCallback; 187 final WeakReference<VoiceInteractionSession> mSession; 188 189 Request(IVoiceInteractorCallback callback, VoiceInteractionSession session) { 190 mCallback = callback; 191 mSession = session.mWeakRef; 192 } 193 194 void finishRequest() { 195 VoiceInteractionSession session = mSession.get(); 196 if (session == null) { 197 throw new IllegalStateException("VoiceInteractionSession has been destroyed"); 198 } 199 Request req = session.removeRequest(mInterface.asBinder()); 200 if (req == null) { 201 throw new IllegalStateException("Request not active: " + this); 202 } else if (req != this) { 203 throw new IllegalStateException("Current active request " + req 204 + " not same as calling request " + this); 205 } 206 } 207 208 public void sendConfirmResult(boolean confirmed, Bundle result) { 209 try { 210 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface 211 + " confirmed=" + confirmed + " result=" + result); 212 finishRequest(); 213 mCallback.deliverConfirmationResult(mInterface, confirmed, result); 214 } catch (RemoteException e) { 215 } 216 } 217 218 public void sendCompleteVoiceResult(Bundle result) { 219 try { 220 if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface 221 + " result=" + result); 222 finishRequest(); 223 mCallback.deliverCompleteVoiceResult(mInterface, result); 224 } catch (RemoteException e) { 225 } 226 } 227 228 public void sendAbortVoiceResult(Bundle result) { 229 try { 230 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface 231 + " result=" + result); 232 finishRequest(); 233 mCallback.deliverAbortVoiceResult(mInterface, result); 234 } catch (RemoteException e) { 235 } 236 } 237 238 public void sendCommandResult(boolean complete, Bundle result) { 239 try { 240 if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface 241 + " result=" + result); 242 finishRequest(); 243 mCallback.deliverCommandResult(mInterface, complete, result); 244 } catch (RemoteException e) { 245 } 246 } 247 248 public void sendCancelResult() { 249 try { 250 if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface); 251 finishRequest(); 252 mCallback.deliverCancel(mInterface); 253 } catch (RemoteException e) { 254 } 255 } 256 } 257 258 /** 259 * @hide 260 */ 261 @SystemApi 262 public static class Caller { 263 final String packageName; 264 final int uid; 265 266 Caller(String _packageName, int _uid) { 267 packageName = _packageName; 268 uid = _uid; 269 } 270 } 271 272 static final int MSG_START_CONFIRMATION = 1; 273 static final int MSG_START_COMPLETE_VOICE = 2; 274 static final int MSG_START_ABORT_VOICE = 3; 275 static final int MSG_START_COMMAND = 4; 276 static final int MSG_SUPPORTS_COMMANDS = 5; 277 static final int MSG_CANCEL = 6; 278 279 static final int MSG_TASK_STARTED = 100; 280 static final int MSG_TASK_FINISHED = 101; 281 static final int MSG_CLOSE_SYSTEM_DIALOGS = 102; 282 static final int MSG_DESTROY = 103; 283 284 class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { 285 @Override 286 public void executeMessage(Message msg) { 287 SomeArgs args; 288 switch (msg.what) { 289 case MSG_START_CONFIRMATION: 290 args = (SomeArgs)msg.obj; 291 if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface 292 + " prompt=" + args.arg3 + " extras=" + args.arg4); 293 onConfirm((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3, 294 (Bundle)args.arg4); 295 break; 296 case MSG_START_COMPLETE_VOICE: 297 args = (SomeArgs)msg.obj; 298 if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((Request) args.arg2).mInterface 299 + " message=" + args.arg3 + " extras=" + args.arg4); 300 onCompleteVoice((Caller) args.arg1, (Request) args.arg2, 301 (CharSequence) args.arg3, (Bundle) args.arg4); 302 break; 303 case MSG_START_ABORT_VOICE: 304 args = (SomeArgs)msg.obj; 305 if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + ((Request) args.arg2).mInterface 306 + " message=" + args.arg3 + " extras=" + args.arg4); 307 onAbortVoice((Caller) args.arg1, (Request) args.arg2, (CharSequence) args.arg3, 308 (Bundle) args.arg4); 309 break; 310 case MSG_START_COMMAND: 311 args = (SomeArgs)msg.obj; 312 if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface 313 + " command=" + args.arg3 + " extras=" + args.arg4); 314 onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3, 315 (Bundle) args.arg4); 316 break; 317 case MSG_SUPPORTS_COMMANDS: 318 args = (SomeArgs)msg.obj; 319 if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2); 320 args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2); 321 break; 322 case MSG_CANCEL: 323 args = (SomeArgs)msg.obj; 324 if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface); 325 onCancel((Request)args.arg1); 326 break; 327 case MSG_TASK_STARTED: 328 if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj 329 + " taskId=" + msg.arg1); 330 onTaskStarted((Intent) msg.obj, msg.arg1); 331 break; 332 case MSG_TASK_FINISHED: 333 if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj 334 + " taskId=" + msg.arg1); 335 onTaskFinished((Intent) msg.obj, msg.arg1); 336 break; 337 case MSG_CLOSE_SYSTEM_DIALOGS: 338 if (DEBUG) Log.d(TAG, "onCloseSystemDialogs"); 339 onCloseSystemDialogs(); 340 break; 341 case MSG_DESTROY: 342 if (DEBUG) Log.d(TAG, "doDestroy"); 343 doDestroy(); 344 break; 345 } 346 } 347 348 @Override 349 public void onBackPressed() { 350 VoiceInteractionSession.this.onBackPressed(); 351 } 352 } 353 354 final MyCallbacks mCallbacks = new MyCallbacks(); 355 356 /** 357 * @hide 358 * Information about where interesting parts of the input method UI appear. 359 */ 360 @SystemApi 361 public static final class Insets { 362 /** 363 * This is the part of the UI that is the main content. It is 364 * used to determine the basic space needed, to resize/pan the 365 * application behind. It is assumed that this inset does not 366 * change very much, since any change will cause a full resize/pan 367 * of the application behind. This value is relative to the top edge 368 * of the input method window. 369 */ 370 public final Rect contentInsets = new Rect(); 371 372 /** 373 * This is the region of the UI that is touchable. It is used when 374 * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}. 375 * The region should be specified relative to the origin of the window frame. 376 */ 377 public final Region touchableRegion = new Region(); 378 379 /** 380 * Option for {@link #touchableInsets}: the entire window frame 381 * can be touched. 382 */ 383 public static final int TOUCHABLE_INSETS_FRAME 384 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; 385 386 /** 387 * Option for {@link #touchableInsets}: the area inside of 388 * the content insets can be touched. 389 */ 390 public static final int TOUCHABLE_INSETS_CONTENT 391 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; 392 393 /** 394 * Option for {@link #touchableInsets}: the region specified by 395 * {@link #touchableRegion} can be touched. 396 */ 397 public static final int TOUCHABLE_INSETS_REGION 398 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 399 400 /** 401 * Determine which area of the window is touchable by the user. May 402 * be one of: {@link #TOUCHABLE_INSETS_FRAME}, 403 * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}. 404 */ 405 public int touchableInsets; 406 } 407 408 final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = 409 new ViewTreeObserver.OnComputeInternalInsetsListener() { 410 public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { 411 onComputeInsets(mTmpInsets); 412 info.contentInsets.set(mTmpInsets.contentInsets); 413 info.visibleInsets.set(mTmpInsets.contentInsets); 414 info.touchableRegion.set(mTmpInsets.touchableRegion); 415 info.setTouchableInsets(mTmpInsets.touchableInsets); 416 } 417 }; 418 419 public VoiceInteractionSession(Context context) { 420 this(context, new Handler()); 421 } 422 423 public VoiceInteractionSession(Context context, Handler handler) { 424 mContext = context; 425 mHandlerCaller = new HandlerCaller(context, handler.getLooper(), 426 mCallbacks, true); 427 } 428 429 Request newRequest(IVoiceInteractorCallback callback) { 430 synchronized (this) { 431 Request req = new Request(callback, this); 432 mActiveRequests.put(req.mInterface.asBinder(), req); 433 return req; 434 } 435 } 436 437 Request removeRequest(IBinder reqInterface) { 438 synchronized (this) { 439 return mActiveRequests.remove(reqInterface); 440 } 441 } 442 443 void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) { 444 mSystemService = service; 445 mToken = token; 446 onCreate(args); 447 } 448 449 void doDestroy() { 450 onDestroy(); 451 if (mInitialized) { 452 mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener( 453 mInsetsComputer); 454 if (mWindowAdded) { 455 mWindow.dismiss(); 456 mWindowAdded = false; 457 } 458 mInitialized = false; 459 } 460 } 461 462 void initViews() { 463 mInitialized = true; 464 465 mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession); 466 mRootView = mInflater.inflate( 467 com.android.internal.R.layout.voice_interaction_session, null); 468 mRootView.setSystemUiVisibility( 469 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 470 mWindow.setContentView(mRootView); 471 mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer); 472 473 mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content); 474 } 475 476 /** 477 * @hide 478 */ 479 @SystemApi 480 public void showWindow() { 481 if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded 482 + " mWindowVisible=" + mWindowVisible); 483 484 if (mInShowWindow) { 485 Log.w(TAG, "Re-entrance in to showWindow"); 486 return; 487 } 488 489 try { 490 mInShowWindow = true; 491 if (!mWindowVisible) { 492 mWindowVisible = true; 493 if (!mWindowAdded) { 494 mWindowAdded = true; 495 View v = onCreateContentView(); 496 if (v != null) { 497 setContentView(v); 498 } 499 } 500 mWindow.show(); 501 } 502 } finally { 503 mWindowWasVisible = true; 504 mInShowWindow = false; 505 } 506 } 507 508 /** 509 * @hide 510 */ 511 @SystemApi 512 public void hideWindow() { 513 if (mWindowVisible) { 514 mWindow.hide(); 515 mWindowVisible = false; 516 } 517 } 518 519 /** 520 * @hide 521 * You can call this to customize the theme used by your IME's window. 522 * This must be set before {@link #onCreate}, so you 523 * will typically call it in your constructor with the resource ID 524 * of your custom theme. 525 */ 526 @SystemApi 527 public void setTheme(int theme) { 528 if (mWindow != null) { 529 throw new IllegalStateException("Must be called before onCreate()"); 530 } 531 mTheme = theme; 532 } 533 534 /** 535 * @hide 536 * Ask that a new activity be started for voice interaction. This will create a 537 * new dedicated task in the activity manager for this voice interaction session; 538 * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK} 539 * will be set for you to make it a new task. 540 * 541 * <p>The newly started activity will be displayed to the user in a special way, as 542 * a layer under the voice interaction UI.</p> 543 * 544 * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor} 545 * through which it can perform voice interactions through your session. These requests 546 * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands}, 547 * {@link #onConfirm}, {@link #onCommand}, and {@link #onCancel}. 548 * 549 * <p>You will receive a call to {@link #onTaskStarted} when the task starts up 550 * and {@link #onTaskFinished} when the last activity has finished. 551 * 552 * @param intent The Intent to start this voice interaction. The given Intent will 553 * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since 554 * this is part of a voice interaction. 555 */ 556 @SystemApi 557 public void startVoiceActivity(Intent intent) { 558 if (mToken == null) { 559 throw new IllegalStateException("Can't call before onCreate()"); 560 } 561 try { 562 intent.migrateExtraStreamToClipData(); 563 intent.prepareToLeaveProcess(); 564 int res = mSystemService.startVoiceActivity(mToken, intent, 565 intent.resolveType(mContext.getContentResolver())); 566 Instrumentation.checkStartActivityResult(res, intent); 567 } catch (RemoteException e) { 568 } 569 } 570 571 /** 572 * @hide 573 * Convenience for inflating views. 574 */ 575 @SystemApi 576 public LayoutInflater getLayoutInflater() { 577 return mInflater; 578 } 579 580 /** 581 * @hide 582 * Retrieve the window being used to show the session's UI. 583 */ 584 @SystemApi 585 public Dialog getWindow() { 586 return mWindow; 587 } 588 589 /** 590 * Finish the session. 591 */ 592 public void finish() { 593 if (mToken == null) { 594 throw new IllegalStateException("Can't call before onCreate()"); 595 } 596 hideWindow(); 597 try { 598 mSystemService.finish(mToken); 599 } catch (RemoteException e) { 600 } 601 } 602 603 /** 604 * Initiatize a new session. 605 * 606 * @param args The arguments that were supplied to 607 * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}. 608 */ 609 public void onCreate(Bundle args) { 610 mTheme = mTheme != 0 ? mTheme 611 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession; 612 mInflater = (LayoutInflater)mContext.getSystemService( 613 Context.LAYOUT_INFLATER_SERVICE); 614 mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme, 615 mCallbacks, this, mDispatcherState, 616 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true); 617 mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 618 initViews(); 619 mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT); 620 mWindow.setToken(mToken); 621 } 622 623 /** 624 * Last callback to the session as it is being finished. 625 */ 626 public void onDestroy() { 627 } 628 629 /** 630 * @hide 631 * Hook in which to create the session's UI. 632 */ 633 @SystemApi 634 public View onCreateContentView() { 635 return null; 636 } 637 638 public void setContentView(View view) { 639 mContentFrame.removeAllViews(); 640 mContentFrame.addView(view, new FrameLayout.LayoutParams( 641 ViewGroup.LayoutParams.MATCH_PARENT, 642 ViewGroup.LayoutParams.WRAP_CONTENT)); 643 644 } 645 646 /** 647 * @hide 648 */ 649 @SystemApi 650 public boolean onKeyDown(int keyCode, KeyEvent event) { 651 return false; 652 } 653 654 /** 655 * @hide 656 */ 657 @SystemApi 658 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 659 return false; 660 } 661 662 /** 663 * @hide 664 */ 665 @SystemApi 666 public boolean onKeyUp(int keyCode, KeyEvent event) { 667 return false; 668 } 669 670 /** 671 * @hide 672 */ 673 @SystemApi 674 public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { 675 return false; 676 } 677 678 /** 679 * @hide 680 */ 681 @SystemApi 682 public void onBackPressed() { 683 finish(); 684 } 685 686 /** 687 * Sessions automatically watch for requests that all system UI be closed (such as when 688 * the user presses HOME), which will appear here. The default implementation always 689 * calls {@link #finish}. 690 */ 691 public void onCloseSystemDialogs() { 692 finish(); 693 } 694 695 /** 696 * @hide 697 * Compute the interesting insets into your UI. The default implementation 698 * uses the entire window frame as the insets. The default touchable 699 * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}. 700 * 701 * @param outInsets Fill in with the current UI insets. 702 */ 703 @SystemApi 704 public void onComputeInsets(Insets outInsets) { 705 int[] loc = mTmpLocation; 706 View decor = getWindow().getWindow().getDecorView(); 707 decor.getLocationInWindow(loc); 708 outInsets.contentInsets.top = 0; 709 outInsets.contentInsets.left = 0; 710 outInsets.contentInsets.right = 0; 711 outInsets.contentInsets.bottom = 0; 712 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME; 713 outInsets.touchableRegion.setEmpty(); 714 } 715 716 /** 717 * @hide 718 * @SystemApi 719 * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)} 720 * has actually started. 721 * 722 * @param intent The original {@link Intent} supplied to 723 * {@link #startVoiceActivity(android.content.Intent)}. 724 * @param taskId Unique ID of the now running task. 725 */ 726 public void onTaskStarted(Intent intent, int taskId) { 727 } 728 729 /** 730 * @hide 731 * @SystemApi 732 * Called when the last activity of a task initiated by 733 * {@link #startVoiceActivity(android.content.Intent)} has finished. The default 734 * implementation calls {@link #finish()} on the assumption that this represents 735 * the completion of a voice action. You can override the implementation if you would 736 * like a different behavior. 737 * 738 * @param intent The original {@link Intent} supplied to 739 * {@link #startVoiceActivity(android.content.Intent)}. 740 * @param taskId Unique ID of the finished task. 741 */ 742 public void onTaskFinished(Intent intent, int taskId) { 743 finish(); 744 } 745 746 /** 747 * @hide 748 * @SystemApi 749 * Request to query for what extended commands the session supports. 750 * 751 * @param caller Who is making the request. 752 * @param commands An array of commands that are being queried. 753 * @return Return an array of booleans indicating which of each entry in the 754 * command array is supported. A true entry in the array indicates the command 755 * is supported; false indicates it is not. The default implementation returns 756 * an array of all false entries. 757 */ 758 public boolean[] onGetSupportedCommands(Caller caller, String[] commands) { 759 return new boolean[commands.length]; 760 } 761 762 /** 763 * @hide 764 * @SystemApi 765 * Request to confirm with the user before proceeding with an unrecoverable operation, 766 * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest 767 * VoiceInteractor.ConfirmationRequest}. 768 * 769 * @param caller Who is making the request. 770 * @param request The active request. 771 * @param prompt The prompt informing the user of what will happen, as per 772 * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}. 773 * @param extras Any additional information, as per 774 * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}. 775 */ 776 public abstract void onConfirm(Caller caller, Request request, CharSequence prompt, 777 Bundle extras); 778 779 /** 780 * @hide 781 * @SystemApi 782 * Request to complete the voice interaction session because the voice activity successfully 783 * completed its interaction using voice. Corresponds to 784 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 785 * VoiceInteractor.CompleteVoiceRequest}. The default implementation just sends an empty 786 * confirmation back to allow the activity to exit. 787 * 788 * @param caller Who is making the request. 789 * @param request The active request. 790 * @param message The message informing the user of the problem, as per 791 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 792 * VoiceInteractor.CompleteVoiceRequest}. 793 * @param extras Any additional information, as per 794 * {@link android.app.VoiceInteractor.CompleteVoiceRequest 795 * VoiceInteractor.CompleteVoiceRequest}. 796 */ 797 public void onCompleteVoice(Caller caller, Request request, CharSequence message, 798 Bundle extras) { 799 request.sendCompleteVoiceResult(null); 800 } 801 802 /** 803 * @hide 804 * @SystemApi 805 * Request to abort the voice interaction session because the voice activity can not 806 * complete its interaction using voice. Corresponds to 807 * {@link android.app.VoiceInteractor.AbortVoiceRequest 808 * VoiceInteractor.AbortVoiceRequest}. The default implementation just sends an empty 809 * confirmation back to allow the activity to exit. 810 * 811 * @param caller Who is making the request. 812 * @param request The active request. 813 * @param message The message informing the user of the problem, as per 814 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. 815 * @param extras Any additional information, as per 816 * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. 817 */ 818 public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) { 819 request.sendAbortVoiceResult(null); 820 } 821 822 /** 823 * @hide 824 * @SystemApi 825 * Process an arbitrary extended command from the caller, 826 * corresponding to a {@link android.app.VoiceInteractor.CommandRequest 827 * VoiceInteractor.CommandRequest}. 828 * 829 * @param caller Who is making the request. 830 * @param request The active request. 831 * @param command The command that is being executed, as per 832 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. 833 * @param extras Any additional information, as per 834 * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}. 835 */ 836 public abstract void onCommand(Caller caller, Request request, String command, Bundle extras); 837 838 /** 839 * @hide 840 * @SystemApi 841 * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request} 842 * that was previously delivered to {@link #onConfirm} or {@link #onCommand}. 843 * 844 * @param request The request that is being canceled. 845 */ 846 public abstract void onCancel(Request request); 847} 848