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