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