• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.service.voice;
18 
19 import android.annotation.SystemApi;
20 import android.app.Dialog;
21 import android.app.Instrumentation;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.res.TypedArray;
25 import android.graphics.Rect;
26 import android.graphics.Region;
27 import android.inputmethodservice.SoftInputWindow;
28 import android.os.Binder;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.Message;
33 import android.os.RemoteException;
34 import android.util.ArrayMap;
35 import android.util.Log;
36 import android.view.Gravity;
37 import android.view.KeyEvent;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.view.ViewTreeObserver;
42 import android.view.WindowManager;
43 import android.widget.FrameLayout;
44 import com.android.internal.app.IVoiceInteractionManagerService;
45 import com.android.internal.app.IVoiceInteractor;
46 import com.android.internal.app.IVoiceInteractorCallback;
47 import com.android.internal.app.IVoiceInteractorRequest;
48 import com.android.internal.os.HandlerCaller;
49 import com.android.internal.os.SomeArgs;
50 
51 import java.lang.ref.WeakReference;
52 
53 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
54 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
55 
56 /**
57  * An active interaction session, started by a {@link VoiceInteractionService}.
58  */
59 public 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 
Request(IVoiceInteractorCallback callback, VoiceInteractionSession session)189         Request(IVoiceInteractorCallback callback, VoiceInteractionSession session) {
190             mCallback = callback;
191             mSession = session.mWeakRef;
192         }
193 
finishRequest()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 
sendConfirmResult(boolean confirmed, Bundle result)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 
sendCompleteVoiceResult(Bundle result)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 
sendAbortVoiceResult(Bundle result)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 
sendCommandResult(boolean complete, Bundle result)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 
sendCancelResult()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 
Caller(String _packageName, int _uid)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
executeMessage(Message msg)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
onBackPressed()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 
VoiceInteractionSession(Context context)419     public VoiceInteractionSession(Context context) {
420         this(context, new Handler());
421     }
422 
VoiceInteractionSession(Context context, Handler handler)423     public VoiceInteractionSession(Context context, Handler handler) {
424         mContext = context;
425         mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
426                 mCallbacks, true);
427     }
428 
newRequest(IVoiceInteractorCallback callback)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 
removeRequest(IBinder reqInterface)437     Request removeRequest(IBinder reqInterface) {
438         synchronized (this) {
439             Request req = mActiveRequests.get(reqInterface);
440             if (req != null) {
441                 mActiveRequests.remove(req);
442             }
443             return req;
444         }
445     }
446 
doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args)447     void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
448         mSystemService = service;
449         mToken = token;
450         onCreate(args);
451     }
452 
doDestroy()453     void doDestroy() {
454         onDestroy();
455         if (mInitialized) {
456             mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
457                     mInsetsComputer);
458             if (mWindowAdded) {
459                 mWindow.dismiss();
460                 mWindowAdded = false;
461             }
462             mInitialized = false;
463         }
464     }
465 
initViews()466     void initViews() {
467         mInitialized = true;
468 
469         mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
470         mRootView = mInflater.inflate(
471                 com.android.internal.R.layout.voice_interaction_session, null);
472         mRootView.setSystemUiVisibility(
473                 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
474         mWindow.setContentView(mRootView);
475         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
476 
477         mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
478     }
479 
480     /**
481      * @hide
482      */
483     @SystemApi
showWindow()484     public void showWindow() {
485         if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
486                 + " mWindowVisible=" + mWindowVisible);
487 
488         if (mInShowWindow) {
489             Log.w(TAG, "Re-entrance in to showWindow");
490             return;
491         }
492 
493         try {
494             mInShowWindow = true;
495             if (!mWindowVisible) {
496                 mWindowVisible = true;
497                 if (!mWindowAdded) {
498                     mWindowAdded = true;
499                     View v = onCreateContentView();
500                     if (v != null) {
501                         setContentView(v);
502                     }
503                 }
504                 mWindow.show();
505             }
506         } finally {
507             mWindowWasVisible = true;
508             mInShowWindow = false;
509         }
510     }
511 
512     /**
513      * @hide
514      */
515     @SystemApi
hideWindow()516     public void hideWindow() {
517         if (mWindowVisible) {
518             mWindow.hide();
519             mWindowVisible = false;
520         }
521     }
522 
523     /**
524      * @hide
525      * You can call this to customize the theme used by your IME's window.
526      * This must be set before {@link #onCreate}, so you
527      * will typically call it in your constructor with the resource ID
528      * of your custom theme.
529      */
530     @SystemApi
setTheme(int theme)531     public void setTheme(int theme) {
532         if (mWindow != null) {
533             throw new IllegalStateException("Must be called before onCreate()");
534         }
535         mTheme = theme;
536     }
537 
538     /**
539      * @hide
540      * Ask that a new activity be started for voice interaction.  This will create a
541      * new dedicated task in the activity manager for this voice interaction session;
542      * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
543      * will be set for you to make it a new task.
544      *
545      * <p>The newly started activity will be displayed to the user in a special way, as
546      * a layer under the voice interaction UI.</p>
547      *
548      * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor}
549      * through which it can perform voice interactions through your session.  These requests
550      * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands},
551      * {@link #onConfirm}, {@link #onCommand}, and {@link #onCancel}.
552      *
553      * <p>You will receive a call to {@link #onTaskStarted} when the task starts up
554      * and {@link #onTaskFinished} when the last activity has finished.
555      *
556      * @param intent The Intent to start this voice interaction.  The given Intent will
557      * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
558      * this is part of a voice interaction.
559      */
560     @SystemApi
startVoiceActivity(Intent intent)561     public void startVoiceActivity(Intent intent) {
562         if (mToken == null) {
563             throw new IllegalStateException("Can't call before onCreate()");
564         }
565         try {
566             intent.migrateExtraStreamToClipData();
567             intent.prepareToLeaveProcess();
568             int res = mSystemService.startVoiceActivity(mToken, intent,
569                     intent.resolveType(mContext.getContentResolver()));
570             Instrumentation.checkStartActivityResult(res, intent);
571         } catch (RemoteException e) {
572         }
573     }
574 
575     /**
576      * @hide
577      * Convenience for inflating views.
578      */
579     @SystemApi
getLayoutInflater()580     public LayoutInflater getLayoutInflater() {
581         return mInflater;
582     }
583 
584     /**
585      * @hide
586      * Retrieve the window being used to show the session's UI.
587      */
588     @SystemApi
getWindow()589     public Dialog getWindow() {
590         return mWindow;
591     }
592 
593     /**
594      * Finish the session.
595      */
finish()596     public void finish() {
597         if (mToken == null) {
598             throw new IllegalStateException("Can't call before onCreate()");
599         }
600         hideWindow();
601         try {
602             mSystemService.finish(mToken);
603         } catch (RemoteException e) {
604         }
605     }
606 
607     /**
608      * Initiatize a new session.
609      *
610      * @param args The arguments that were supplied to
611      * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
612      */
onCreate(Bundle args)613     public void onCreate(Bundle args) {
614         mTheme = mTheme != 0 ? mTheme
615                 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
616         mInflater = (LayoutInflater)mContext.getSystemService(
617                 Context.LAYOUT_INFLATER_SERVICE);
618         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
619                 mCallbacks, this, mDispatcherState,
620                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true);
621         mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
622         initViews();
623         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
624         mWindow.setToken(mToken);
625     }
626 
627     /**
628      * Last callback to the session as it is being finished.
629      */
onDestroy()630     public void onDestroy() {
631     }
632 
633     /**
634      * @hide
635      * Hook in which to create the session's UI.
636      */
637     @SystemApi
onCreateContentView()638     public View onCreateContentView() {
639         return null;
640     }
641 
setContentView(View view)642     public void setContentView(View view) {
643         mContentFrame.removeAllViews();
644         mContentFrame.addView(view, new FrameLayout.LayoutParams(
645                 ViewGroup.LayoutParams.MATCH_PARENT,
646                 ViewGroup.LayoutParams.WRAP_CONTENT));
647 
648     }
649 
650     /**
651      * @hide
652      */
653     @SystemApi
onKeyDown(int keyCode, KeyEvent event)654     public boolean onKeyDown(int keyCode, KeyEvent event) {
655         return false;
656     }
657 
658     /**
659      * @hide
660      */
661     @SystemApi
onKeyLongPress(int keyCode, KeyEvent event)662     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
663         return false;
664     }
665 
666     /**
667      * @hide
668      */
669     @SystemApi
onKeyUp(int keyCode, KeyEvent event)670     public boolean onKeyUp(int keyCode, KeyEvent event) {
671         return false;
672     }
673 
674     /**
675      * @hide
676      */
677     @SystemApi
onKeyMultiple(int keyCode, int count, KeyEvent event)678     public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
679         return false;
680     }
681 
682     /**
683      * @hide
684      */
685     @SystemApi
onBackPressed()686     public void onBackPressed() {
687         finish();
688     }
689 
690     /**
691      * Sessions automatically watch for requests that all system UI be closed (such as when
692      * the user presses HOME), which will appear here.  The default implementation always
693      * calls {@link #finish}.
694      */
onCloseSystemDialogs()695     public void onCloseSystemDialogs() {
696         finish();
697     }
698 
699     /**
700      * @hide
701      * Compute the interesting insets into your UI.  The default implementation
702      * uses the entire window frame as the insets.  The default touchable
703      * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
704      *
705      * @param outInsets Fill in with the current UI insets.
706      */
707     @SystemApi
onComputeInsets(Insets outInsets)708     public void onComputeInsets(Insets outInsets) {
709         int[] loc = mTmpLocation;
710         View decor = getWindow().getWindow().getDecorView();
711         decor.getLocationInWindow(loc);
712         outInsets.contentInsets.top = 0;
713         outInsets.contentInsets.left = 0;
714         outInsets.contentInsets.right = 0;
715         outInsets.contentInsets.bottom = 0;
716         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
717         outInsets.touchableRegion.setEmpty();
718     }
719 
720     /**
721      * @hide
722      * @SystemApi
723      * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
724      * has actually started.
725      *
726      * @param intent The original {@link Intent} supplied to
727      * {@link #startVoiceActivity(android.content.Intent)}.
728      * @param taskId Unique ID of the now running task.
729      */
onTaskStarted(Intent intent, int taskId)730     public void onTaskStarted(Intent intent, int taskId) {
731     }
732 
733     /**
734      * @hide
735      * @SystemApi
736      * Called when the last activity of a task initiated by
737      * {@link #startVoiceActivity(android.content.Intent)} has finished.  The default
738      * implementation calls {@link #finish()} on the assumption that this represents
739      * the completion of a voice action.  You can override the implementation if you would
740      * like a different behavior.
741      *
742      * @param intent The original {@link Intent} supplied to
743      * {@link #startVoiceActivity(android.content.Intent)}.
744      * @param taskId Unique ID of the finished task.
745      */
onTaskFinished(Intent intent, int taskId)746     public void onTaskFinished(Intent intent, int taskId) {
747         finish();
748     }
749 
750     /**
751      * @hide
752      * @SystemApi
753      * Request to query for what extended commands the session supports.
754      *
755      * @param caller Who is making the request.
756      * @param commands An array of commands that are being queried.
757      * @return Return an array of booleans indicating which of each entry in the
758      * command array is supported.  A true entry in the array indicates the command
759      * is supported; false indicates it is not.  The default implementation returns
760      * an array of all false entries.
761      */
onGetSupportedCommands(Caller caller, String[] commands)762     public boolean[] onGetSupportedCommands(Caller caller, String[] commands) {
763         return new boolean[commands.length];
764     }
765 
766     /**
767      * @hide
768      * @SystemApi
769      * Request to confirm with the user before proceeding with an unrecoverable operation,
770      * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
771      * VoiceInteractor.ConfirmationRequest}.
772      *
773      * @param caller Who is making the request.
774      * @param request The active request.
775      * @param prompt The prompt informing the user of what will happen, as per
776      * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}.
777      * @param extras Any additional information, as per
778      * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}.
779      */
onConfirm(Caller caller, Request request, CharSequence prompt, Bundle extras)780     public abstract void onConfirm(Caller caller, Request request, CharSequence prompt,
781             Bundle extras);
782 
783     /**
784      * @hide
785      * @SystemApi
786      * Request to complete the voice interaction session because the voice activity successfully
787      * completed its interaction using voice.  Corresponds to
788      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
789      * VoiceInteractor.CompleteVoiceRequest}.  The default implementation just sends an empty
790      * confirmation back to allow the activity to exit.
791      *
792      * @param caller Who is making the request.
793      * @param request The active request.
794      * @param message The message informing the user of the problem, as per
795      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
796      * VoiceInteractor.CompleteVoiceRequest}.
797      * @param extras Any additional information, as per
798      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
799      * VoiceInteractor.CompleteVoiceRequest}.
800      */
onCompleteVoice(Caller caller, Request request, CharSequence message, Bundle extras)801     public void onCompleteVoice(Caller caller, Request request, CharSequence message,
802            Bundle extras) {
803         request.sendCompleteVoiceResult(null);
804     }
805 
806     /**
807      * @hide
808      * @SystemApi
809      * Request to abort the voice interaction session because the voice activity can not
810      * complete its interaction using voice.  Corresponds to
811      * {@link android.app.VoiceInteractor.AbortVoiceRequest
812      * VoiceInteractor.AbortVoiceRequest}.  The default implementation just sends an empty
813      * confirmation back to allow the activity to exit.
814      *
815      * @param caller Who is making the request.
816      * @param request The active request.
817      * @param message The message informing the user of the problem, as per
818      * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
819      * @param extras Any additional information, as per
820      * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
821      */
onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras)822     public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) {
823         request.sendAbortVoiceResult(null);
824     }
825 
826     /**
827      * @hide
828      * @SystemApi
829      * Process an arbitrary extended command from the caller,
830      * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
831      * VoiceInteractor.CommandRequest}.
832      *
833      * @param caller Who is making the request.
834      * @param request The active request.
835      * @param command The command that is being executed, as per
836      * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
837      * @param extras Any additional information, as per
838      * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
839      */
onCommand(Caller caller, Request request, String command, Bundle extras)840     public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
841 
842     /**
843      * @hide
844      * @SystemApi
845      * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
846      * that was previously delivered to {@link #onConfirm} or {@link #onCommand}.
847      *
848      * @param request The request that is being canceled.
849      */
onCancel(Request request)850     public abstract void onCancel(Request request);
851 }
852