VoiceInteractionSession.java revision d7c0395d26694c594c3e64b16ab647c971aeb422
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            Request req = mActiveRequests.get(reqInterface);
440            if (req != null) {
441                mActiveRequests.remove(req);
442            }
443            return req;
444        }
445    }
446
447    void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
448        mSystemService = service;
449        mToken = token;
450        onCreate(args);
451    }
452
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
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
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
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
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
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
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
589    public Dialog getWindow() {
590        return mWindow;
591    }
592
593    /**
594     * Finish the session.
595     */
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     */
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     */
630    public void onDestroy() {
631    }
632
633    /**
634     * @hide
635     * Hook in which to create the session's UI.
636     */
637    @SystemApi
638    public View onCreateContentView() {
639        return null;
640    }
641
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
654    public boolean onKeyDown(int keyCode, KeyEvent event) {
655        return false;
656    }
657
658    /**
659     * @hide
660     */
661    @SystemApi
662    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
663        return false;
664    }
665
666    /**
667     * @hide
668     */
669    @SystemApi
670    public boolean onKeyUp(int keyCode, KeyEvent event) {
671        return false;
672    }
673
674    /**
675     * @hide
676     */
677    @SystemApi
678    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
679        return false;
680    }
681
682    /**
683     * @hide
684     */
685    @SystemApi
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     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
850    public abstract void onCancel(Request request);
851}
852