VoiceInteractionSession.java revision 1b4447f728eab763beb2da28d3cf64574729c556
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        /**
326         * Check whether this request is currently active.  A request becomes inactive after
327         * calling {@link #cancel} or a final result method that completes the request.  After
328         * this point, further interactions with the request will result in
329         * {@link java.lang.IllegalStateException} errors; you should not catch these errors,
330         * but can use this method if you need to determine the state of the request.  Returns
331         * true if the request is still active.
332         */
333        public boolean isActive() {
334            VoiceInteractionSession session = mSession.get();
335            if (session == null) {
336                return false;
337            }
338            return session.isRequestActive(mInterface.asBinder());
339        }
340
341        void finishRequest() {
342            VoiceInteractionSession session = mSession.get();
343            if (session == null) {
344                throw new IllegalStateException("VoiceInteractionSession has been destroyed");
345            }
346            Request req = session.removeRequest(mInterface.asBinder());
347            if (req == null) {
348                throw new IllegalStateException("Request not active: " + this);
349            } else if (req != this) {
350                throw new IllegalStateException("Current active request " + req
351                        + " not same as calling request " + this);
352            }
353        }
354
355        /**
356         * Ask the app to cancel this current request.
357         * This also finishes the request (it is no longer active).
358         */
359        public void cancel() {
360            try {
361                if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
362                finishRequest();
363                mCallback.deliverCancel(mInterface);
364            } catch (RemoteException e) {
365            }
366        }
367    }
368
369    /**
370     * A request for confirmation from the user of an operation, as per
371     * {@link android.app.VoiceInteractor.ConfirmationRequest
372     * VoiceInteractor.ConfirmationRequest}.
373     */
374    public static final class ConfirmationRequest extends Request {
375        final VoiceInteractor.Prompt mPrompt;
376
377        ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback,
378                VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
379            super(packageName, uid, callback, session, extras);
380            mPrompt = prompt;
381        }
382
383        /**
384         * Return the prompt informing the user of what will happen, as per
385         * {@link android.app.VoiceInteractor.ConfirmationRequest
386         * VoiceInteractor.ConfirmationRequest}.
387         */
388        @Nullable
389        public VoiceInteractor.Prompt getVoicePrompt() {
390            return mPrompt;
391        }
392
393        /**
394         * Return the prompt informing the user of what will happen, as per
395         * {@link android.app.VoiceInteractor.ConfirmationRequest
396         * VoiceInteractor.ConfirmationRequest}.
397         * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
398         */
399        @Nullable
400        public CharSequence getPrompt() {
401            return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
402        }
403
404        /**
405         * Report that the voice interactor has confirmed the operation with the user, resulting
406         * in a call to
407         * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult
408         * VoiceInteractor.ConfirmationRequest.onConfirmationResult}.
409         * This finishes the request (it is no longer active).
410         */
411        public void sendConfirmationResult(boolean confirmed, Bundle result) {
412            try {
413                if (DEBUG) Log.d(TAG, "sendConfirmationResult: req=" + mInterface
414                        + " confirmed=" + confirmed + " result=" + result);
415                finishRequest();
416                mCallback.deliverConfirmationResult(mInterface, confirmed, result);
417            } catch (RemoteException e) {
418            }
419        }
420    }
421
422    /**
423     * A request for the user to pick from a set of option, as per
424     * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
425     */
426    public static final class PickOptionRequest extends Request {
427        final VoiceInteractor.Prompt mPrompt;
428        final VoiceInteractor.PickOptionRequest.Option[] mOptions;
429
430        PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback,
431                VoiceInteractionSession session, VoiceInteractor.Prompt prompt,
432                VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
433            super(packageName, uid, callback, session, extras);
434            mPrompt = prompt;
435            mOptions = options;
436        }
437
438        /**
439         * Return the prompt informing the user of what they are picking, as per
440         * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
441         */
442        @Nullable
443        public VoiceInteractor.Prompt getVoicePrompt() {
444            return mPrompt;
445        }
446
447        /**
448         * Return the prompt informing the user of what they are picking, as per
449         * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
450         * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts.
451         */
452        @Nullable
453        public CharSequence getPrompt() {
454            return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
455        }
456
457        /**
458         * Return the set of options the user is picking from, as per
459         * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
460         */
461        public VoiceInteractor.PickOptionRequest.Option[] getOptions() {
462            return mOptions;
463        }
464
465        void sendPickOptionResult(boolean finished,
466                VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
467            try {
468                if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface
469                        + " finished=" + finished + " selections=" + selections
470                        + " result=" + result);
471                if (finished) {
472                    finishRequest();
473                }
474                mCallback.deliverPickOptionResult(mInterface, finished, selections, result);
475            } catch (RemoteException e) {
476            }
477        }
478
479        /**
480         * Report an intermediate option selection from the request, without completing it (the
481         * request is still active and the app is waiting for the final option selection),
482         * resulting in a call to
483         * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
484         * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
485         */
486        public void sendIntermediatePickOptionResult(
487                VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
488            sendPickOptionResult(false, selections, result);
489        }
490
491        /**
492         * Report the final option selection for the request, completing the request
493         * and resulting in a call to
494         * {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
495         * VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
496         * This finishes the request (it is no longer active).
497         */
498        public void sendPickOptionResult(
499                VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
500            sendPickOptionResult(true, selections, result);
501        }
502    }
503
504    /**
505     * A request to simply inform the user that the voice operation has completed, as per
506     * {@link android.app.VoiceInteractor.CompleteVoiceRequest
507     * VoiceInteractor.CompleteVoiceRequest}.
508     */
509    public static final class CompleteVoiceRequest extends Request {
510        final VoiceInteractor.Prompt mPrompt;
511
512        CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
513                VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
514            super(packageName, uid, callback, session, extras);
515            mPrompt = prompt;
516        }
517
518        /**
519         * Return the message informing the user of the completion, as per
520         * {@link android.app.VoiceInteractor.CompleteVoiceRequest
521         * VoiceInteractor.CompleteVoiceRequest}.
522         */
523        @Nullable
524        public VoiceInteractor.Prompt getVoicePrompt() {
525            return mPrompt;
526        }
527
528        /**
529         * Return the message informing the user of the completion, as per
530         * {@link android.app.VoiceInteractor.CompleteVoiceRequest
531         * VoiceInteractor.CompleteVoiceRequest}.
532         * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
533         */
534        @Nullable
535        public CharSequence getMessage() {
536            return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
537        }
538
539        /**
540         * Report that the voice interactor has finished completing the voice operation, resulting
541         * in a call to
542         * {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult
543         * VoiceInteractor.CompleteVoiceRequest.onCompleteResult}.
544         * This finishes the request (it is no longer active).
545         */
546        public void sendCompleteResult(Bundle result) {
547            try {
548                if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface
549                        + " result=" + result);
550                finishRequest();
551                mCallback.deliverCompleteVoiceResult(mInterface, result);
552            } catch (RemoteException e) {
553            }
554        }
555    }
556
557    /**
558     * A request to report that the current user interaction can not be completed with voice, as per
559     * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
560     */
561    public static final class AbortVoiceRequest extends Request {
562        final VoiceInteractor.Prompt mPrompt;
563
564        AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback,
565                VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) {
566            super(packageName, uid, callback, session, extras);
567            mPrompt = prompt;
568        }
569
570        /**
571         * Return the message informing the user of the problem, as per
572         * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
573         */
574        @Nullable
575        public VoiceInteractor.Prompt getVoicePrompt() {
576            return mPrompt;
577        }
578
579        /**
580         * Return the message informing the user of the problem, as per
581         * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
582         * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message.
583         */
584        @Nullable
585        public CharSequence getMessage() {
586            return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null);
587        }
588
589        /**
590         * Report that the voice interactor has finished aborting the voice operation, resulting
591         * in a call to
592         * {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult
593         * VoiceInteractor.AbortVoiceRequest.onAbortResult}.  This finishes the request (it
594         * is no longer active).
595         */
596        public void sendAbortResult(Bundle result) {
597            try {
598                if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
599                        + " result=" + result);
600                finishRequest();
601                mCallback.deliverAbortVoiceResult(mInterface, result);
602            } catch (RemoteException e) {
603            }
604        }
605    }
606
607    /**
608     * A generic vendor-specific request, as per
609     * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
610     */
611    public static final class CommandRequest extends Request {
612        final String mCommand;
613
614        CommandRequest(String packageName, int uid, IVoiceInteractorCallback callback,
615                VoiceInteractionSession session, String command, Bundle extras) {
616            super(packageName, uid, callback, session, extras);
617            mCommand = command;
618        }
619
620        /**
621         * Return the command that is being executed, as per
622         * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
623         */
624        public String getCommand() {
625            return mCommand;
626        }
627
628        void sendCommandResult(boolean finished, Bundle result) {
629            try {
630                if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
631                        + " result=" + result);
632                if (finished) {
633                    finishRequest();
634                }
635                mCallback.deliverCommandResult(mInterface, finished, result);
636            } catch (RemoteException e) {
637            }
638        }
639
640        /**
641         * Report an intermediate result of the request, without completing it (the request
642         * is still active and the app is waiting for the final result), resulting in a call to
643         * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
644         * VoiceInteractor.CommandRequest.onCommandResult} with false for isCompleted.
645         */
646        public void sendIntermediateResult(Bundle result) {
647            sendCommandResult(false, result);
648        }
649
650        /**
651         * Report the final result of the request, completing the request and resulting in a call to
652         * {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
653         * VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted.
654         * This finishes the request (it is no longer active).
655         */
656        public void sendResult(Bundle result) {
657            sendCommandResult(true, result);
658        }
659    }
660
661    static final int MSG_START_CONFIRMATION = 1;
662    static final int MSG_START_PICK_OPTION = 2;
663    static final int MSG_START_COMPLETE_VOICE = 3;
664    static final int MSG_START_ABORT_VOICE = 4;
665    static final int MSG_START_COMMAND = 5;
666    static final int MSG_SUPPORTS_COMMANDS = 6;
667    static final int MSG_CANCEL = 7;
668
669    static final int MSG_TASK_STARTED = 100;
670    static final int MSG_TASK_FINISHED = 101;
671    static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
672    static final int MSG_DESTROY = 103;
673    static final int MSG_HANDLE_ASSIST = 104;
674    static final int MSG_HANDLE_SCREENSHOT = 105;
675    static final int MSG_SHOW = 106;
676    static final int MSG_HIDE = 107;
677
678    class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
679        @Override
680        public void executeMessage(Message msg) {
681            SomeArgs args = null;
682            switch (msg.what) {
683                case MSG_START_CONFIRMATION:
684                    if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
685                    onRequestConfirmation((ConfirmationRequest) msg.obj);
686                    break;
687                case MSG_START_PICK_OPTION:
688                    if (DEBUG) Log.d(TAG, "onPickOption: req=" + msg.obj);
689                    onRequestPickOption((PickOptionRequest) msg.obj);
690                    break;
691                case MSG_START_COMPLETE_VOICE:
692                    if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + msg.obj);
693                    onRequestCompleteVoice((CompleteVoiceRequest) msg.obj);
694                    break;
695                case MSG_START_ABORT_VOICE:
696                    if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + msg.obj);
697                    onRequestAbortVoice((AbortVoiceRequest) msg.obj);
698                    break;
699                case MSG_START_COMMAND:
700                    if (DEBUG) Log.d(TAG, "onCommand: req=" + msg.obj);
701                    onRequestCommand((CommandRequest) msg.obj);
702                    break;
703                case MSG_SUPPORTS_COMMANDS:
704                    args = (SomeArgs)msg.obj;
705                    if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
706                    args.arg1 = onGetSupportedCommands((String[]) args.arg1);
707                    args.complete();
708                    args = null;
709                    break;
710                case MSG_CANCEL:
711                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
712                    onCancelRequest((Request) msg.obj);
713                    break;
714                case MSG_TASK_STARTED:
715                    if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
716                            + " taskId=" + msg.arg1);
717                    onTaskStarted((Intent) msg.obj, msg.arg1);
718                    break;
719                case MSG_TASK_FINISHED:
720                    if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
721                            + " taskId=" + msg.arg1);
722                    onTaskFinished((Intent) msg.obj, msg.arg1);
723                    break;
724                case MSG_CLOSE_SYSTEM_DIALOGS:
725                    if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
726                    onCloseSystemDialogs();
727                    break;
728                case MSG_DESTROY:
729                    if (DEBUG) Log.d(TAG, "doDestroy");
730                    doDestroy();
731                    break;
732                case MSG_HANDLE_ASSIST:
733                    args = (SomeArgs)msg.obj;
734                    if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
735                            + " structure=" + args.arg2 + " content=" + args.arg3);
736                    doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
737                            (Throwable) args.arg3, (AssistContent) args.arg4);
738                    break;
739                case MSG_HANDLE_SCREENSHOT:
740                    if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
741                    onHandleScreenshot((Bitmap) msg.obj);
742                    break;
743                case MSG_SHOW:
744                    args = (SomeArgs)msg.obj;
745                    if (DEBUG) Log.d(TAG, "doShow: args=" + args.arg1
746                            + " flags=" + msg.arg1
747                            + " showCallback=" + args.arg2);
748                    doShow((Bundle) args.arg1, msg.arg1,
749                            (IVoiceInteractionSessionShowCallback) args.arg2);
750                    break;
751                case MSG_HIDE:
752                    if (DEBUG) Log.d(TAG, "doHide");
753                    doHide();
754                    break;
755            }
756            if (args != null) {
757                args.recycle();
758            }
759        }
760
761        @Override
762        public void onBackPressed() {
763            VoiceInteractionSession.this.onBackPressed();
764        }
765    }
766
767    final MyCallbacks mCallbacks = new MyCallbacks();
768
769    /**
770     * Information about where interesting parts of the input method UI appear.
771     */
772    public static final class Insets {
773        /**
774         * This is the part of the UI that is the main content.  It is
775         * used to determine the basic space needed, to resize/pan the
776         * application behind.  It is assumed that this inset does not
777         * change very much, since any change will cause a full resize/pan
778         * of the application behind.  This value is relative to the top edge
779         * of the input method window.
780         */
781        public final Rect contentInsets = new Rect();
782
783        /**
784         * This is the region of the UI that is touchable.  It is used when
785         * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
786         * The region should be specified relative to the origin of the window frame.
787         */
788        public final Region touchableRegion = new Region();
789
790        /**
791         * Option for {@link #touchableInsets}: the entire window frame
792         * can be touched.
793         */
794        public static final int TOUCHABLE_INSETS_FRAME
795                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
796
797        /**
798         * Option for {@link #touchableInsets}: the area inside of
799         * the content insets can be touched.
800         */
801        public static final int TOUCHABLE_INSETS_CONTENT
802                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
803
804        /**
805         * Option for {@link #touchableInsets}: the region specified by
806         * {@link #touchableRegion} can be touched.
807         */
808        public static final int TOUCHABLE_INSETS_REGION
809                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
810
811        /**
812         * Determine which area of the window is touchable by the user.  May
813         * be one of: {@link #TOUCHABLE_INSETS_FRAME},
814         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
815         */
816        public int touchableInsets;
817    }
818
819    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
820            new ViewTreeObserver.OnComputeInternalInsetsListener() {
821        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
822            onComputeInsets(mTmpInsets);
823            info.contentInsets.set(mTmpInsets.contentInsets);
824            info.visibleInsets.set(mTmpInsets.contentInsets);
825            info.touchableRegion.set(mTmpInsets.touchableRegion);
826            info.setTouchableInsets(mTmpInsets.touchableInsets);
827        }
828    };
829
830    public VoiceInteractionSession(Context context) {
831        this(context, new Handler());
832    }
833
834    public VoiceInteractionSession(Context context, Handler handler) {
835        mContext = context;
836        mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
837                mCallbacks, true);
838    }
839
840    public Context getContext() {
841        return mContext;
842    }
843
844    void addRequest(Request req) {
845        synchronized (this) {
846            mActiveRequests.put(req.mInterface.asBinder(), req);
847        }
848    }
849
850    boolean isRequestActive(IBinder reqInterface) {
851        synchronized (this) {
852            return mActiveRequests.containsKey(reqInterface);
853        }
854    }
855
856    Request removeRequest(IBinder reqInterface) {
857        synchronized (this) {
858            return mActiveRequests.remove(reqInterface);
859        }
860    }
861
862    void doCreate(IVoiceInteractionManagerService service, IBinder token) {
863        mSystemService = service;
864        mToken = token;
865        onCreate();
866    }
867
868    void doShow(Bundle args, int flags, final IVoiceInteractionSessionShowCallback showCallback) {
869        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
870                + " mWindowVisible=" + mWindowVisible);
871
872        if (mInShowWindow) {
873            Log.w(TAG, "Re-entrance in to showWindow");
874            return;
875        }
876
877        try {
878            mInShowWindow = true;
879            if (!mWindowVisible) {
880                if (!mWindowAdded) {
881                    mWindowAdded = true;
882                    View v = onCreateContentView();
883                    if (v != null) {
884                        setContentView(v);
885                    }
886                }
887            }
888            onShow(args, flags);
889            if (!mWindowVisible) {
890                mWindowVisible = true;
891                mWindow.show();
892            }
893            if (showCallback != null) {
894                mRootView.invalidate();
895                mRootView.getViewTreeObserver().addOnPreDrawListener(
896                        new ViewTreeObserver.OnPreDrawListener() {
897                            @Override
898                            public boolean onPreDraw() {
899                                mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
900                                try {
901                                    showCallback.onShown();
902                                } catch (RemoteException e) {
903                                    Log.w(TAG, "Error calling onShown", e);
904                                }
905                                return true;
906                            }
907                        });
908            }
909        } finally {
910            mWindowWasVisible = true;
911            mInShowWindow = false;
912        }
913    }
914
915    void doHide() {
916        if (mWindowVisible) {
917            mWindow.hide();
918            mWindowVisible = false;
919            onHide();
920        }
921    }
922
923    void doDestroy() {
924        onDestroy();
925        if (mInitialized) {
926            mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
927                    mInsetsComputer);
928            if (mWindowAdded) {
929                mWindow.dismiss();
930                mWindowAdded = false;
931            }
932            mInitialized = false;
933        }
934    }
935
936    void initViews() {
937        mInitialized = true;
938
939        mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
940        mRootView = mInflater.inflate(
941                com.android.internal.R.layout.voice_interaction_session, null);
942        mRootView.setSystemUiVisibility(
943                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
944                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
945        mWindow.setContentView(mRootView);
946        mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
947
948        mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
949    }
950
951    /**
952     * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
953     * VoiceInteractionService.setDisabledShowContext(int)}.
954     */
955    public void setDisabledShowContext(int flags) {
956        try {
957            mSystemService.setDisabledShowContext(flags);
958        } catch (RemoteException e) {
959        }
960    }
961
962    /**
963     * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
964     * VoiceInteractionService.getDisabledShowContext}.
965     */
966    public int getDisabledShowContext() {
967        try {
968            return mSystemService.getDisabledShowContext();
969        } catch (RemoteException e) {
970            return 0;
971        }
972    }
973
974    /**
975     * Return which show context flags have been disabled by the user through the system
976     * settings UI, so the session will never get this data.  Returned flags are any combination of
977     * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
978     * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
979     * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}.  Note that this only tells you about
980     * global user settings, not about restrictions that may be applied contextual based on
981     * the current application the user is in or other transient states.
982     */
983    public int getUserDisabledShowContext() {
984        try {
985            return mSystemService.getUserDisabledShowContext();
986        } catch (RemoteException e) {
987            return 0;
988        }
989    }
990
991    /**
992     * Show the UI for this session.  This asks the system to go through the process of showing
993     * your UI, which will eventually culminate in {@link #onShow}.  This is similar to calling
994     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
995     * @param args Arbitrary arguments that will be propagated {@link #onShow}.
996     * @param flags Indicates additional optional behavior that should be performed.  May
997     * be any combination of
998     * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
999     * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
1000     * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
1001     * to request that the system generate and deliver assist data on the current foreground
1002     * app as part of showing the session UI.
1003     */
1004    public void show(Bundle args, int flags) {
1005        if (mToken == null) {
1006            throw new IllegalStateException("Can't call before onCreate()");
1007        }
1008        try {
1009            mSystemService.showSessionFromSession(mToken, args, flags);
1010        } catch (RemoteException e) {
1011        }
1012    }
1013
1014    /**
1015     * Hide the session's UI, if currently shown.  Call this when you are done with your
1016     * user interaction.
1017     */
1018    public void hide() {
1019        if (mToken == null) {
1020            throw new IllegalStateException("Can't call before onCreate()");
1021        }
1022        try {
1023            mSystemService.hideSessionFromSession(mToken);
1024        } catch (RemoteException e) {
1025        }
1026    }
1027
1028    /**
1029     * You can call this to customize the theme used by your IME's window.
1030     * This must be set before {@link #onCreate}, so you
1031     * will typically call it in your constructor with the resource ID
1032     * of your custom theme.
1033     */
1034    public void setTheme(int theme) {
1035        if (mWindow != null) {
1036            throw new IllegalStateException("Must be called before onCreate()");
1037        }
1038        mTheme = theme;
1039    }
1040
1041    /**
1042     * Ask that a new activity be started for voice interaction.  This will create a
1043     * new dedicated task in the activity manager for this voice interaction session;
1044     * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
1045     * will be set for you to make it a new task.
1046     *
1047     * <p>The newly started activity will be displayed to the user in a special way, as
1048     * a layer under the voice interaction UI.</p>
1049     *
1050     * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor}
1051     * through which it can perform voice interactions through your session.  These requests
1052     * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands},
1053     * {@link #onRequestConfirmation}, {@link #onRequestPickOption},
1054     * {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1055     * or {@link #onRequestCommand}
1056     *
1057     * <p>You will receive a call to {@link #onTaskStarted} when the task starts up
1058     * and {@link #onTaskFinished} when the last activity has finished.
1059     *
1060     * @param intent The Intent to start this voice interaction.  The given Intent will
1061     * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
1062     * this is part of a voice interaction.
1063     */
1064    public void startVoiceActivity(Intent intent) {
1065        if (mToken == null) {
1066            throw new IllegalStateException("Can't call before onCreate()");
1067        }
1068        try {
1069            intent.migrateExtraStreamToClipData();
1070            intent.prepareToLeaveProcess();
1071            int res = mSystemService.startVoiceActivity(mToken, intent,
1072                    intent.resolveType(mContext.getContentResolver()));
1073            Instrumentation.checkStartActivityResult(res, intent);
1074        } catch (RemoteException e) {
1075        }
1076    }
1077
1078    /**
1079     * Set whether this session will keep the device awake while it is running a voice
1080     * activity.  By default, the system holds a wake lock for it while in this state,
1081     * so that it can work even if the screen is off.  Setting this to false removes that
1082     * wake lock, allowing the CPU to go to sleep.  This is typically used if the
1083     * session decides it has been waiting too long for a response from the user and
1084     * doesn't want to let this continue to drain the battery.
1085     *
1086     * <p>Passing false here will release the wake lock, and you can call later with
1087     * true to re-acquire it.  It will also be automatically re-acquired for you each
1088     * time you start a new voice activity task -- that is when you call
1089     * {@link #startVoiceActivity}.</p>
1090     */
1091    public void setKeepAwake(boolean keepAwake) {
1092        if (mToken == null) {
1093            throw new IllegalStateException("Can't call before onCreate()");
1094        }
1095        try {
1096            mSystemService.setKeepAwake(mToken, keepAwake);
1097        } catch (RemoteException e) {
1098        }
1099    }
1100
1101    /**
1102     * Request that all system dialogs (and status bar shade etc) be closed, allowing
1103     * access to the session's UI.  This will <em>not</em> cause the lock screen to be
1104     * dismissed.
1105     */
1106    public void closeSystemDialogs() {
1107        if (mToken == null) {
1108            throw new IllegalStateException("Can't call before onCreate()");
1109        }
1110        try {
1111            mSystemService.closeSystemDialogs(mToken);
1112        } catch (RemoteException e) {
1113        }
1114    }
1115
1116    /**
1117     * Convenience for inflating views.
1118     */
1119    public LayoutInflater getLayoutInflater() {
1120        return mInflater;
1121    }
1122
1123    /**
1124     * Retrieve the window being used to show the session's UI.
1125     */
1126    public Dialog getWindow() {
1127        return mWindow;
1128    }
1129
1130    /**
1131     * Finish the session.  This completely destroys the session -- the next time it is shown,
1132     * an entirely new one will be created.  You do not normally call this function; instead,
1133     * use {@link #hide} and allow the system to destroy your session if it needs its RAM.
1134     */
1135    public void finish() {
1136        if (mToken == null) {
1137            throw new IllegalStateException("Can't call before onCreate()");
1138        }
1139        try {
1140            mSystemService.finish(mToken);
1141        } catch (RemoteException e) {
1142        }
1143    }
1144
1145    /**
1146     * Initiatize a new session.  At this point you don't know exactly what this
1147     * session will be used for; you will find that out in {@link #onShow}.
1148     */
1149    public void onCreate() {
1150        doOnCreate();
1151    }
1152
1153    private void doOnCreate() {
1154        mTheme = mTheme != 0 ? mTheme
1155                : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
1156        mInflater = (LayoutInflater)mContext.getSystemService(
1157                Context.LAYOUT_INFLATER_SERVICE);
1158        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
1159                mCallbacks, this, mDispatcherState,
1160                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
1161        mWindow.getWindow().addFlags(
1162                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
1163                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
1164                WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
1165        initViews();
1166        mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
1167        mWindow.setToken(mToken);
1168    }
1169
1170    /**
1171     * Called when the session UI is going to be shown.  This is called after
1172     * {@link #onCreateContentView} (if the session's content UI needed to be created) and
1173     * immediately prior to the window being shown.  This may be called while the window
1174     * is already shown, if a show request has come in while it is shown, to allow you to
1175     * update the UI to match the new show arguments.
1176     *
1177     * @param args The arguments that were supplied to
1178     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1179     * @param showFlags The show flags originally provided to
1180     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
1181     */
1182    public void onShow(Bundle args, int showFlags) {
1183    }
1184
1185    /**
1186     * Called immediately after stopping to show the session UI.
1187     */
1188    public void onHide() {
1189    }
1190
1191    /**
1192     * Last callback to the session as it is being finished.
1193     */
1194    public void onDestroy() {
1195    }
1196
1197    /**
1198     * Hook in which to create the session's UI.
1199     */
1200    public View onCreateContentView() {
1201        return null;
1202    }
1203
1204    public void setContentView(View view) {
1205        mContentFrame.removeAllViews();
1206        mContentFrame.addView(view, new FrameLayout.LayoutParams(
1207                ViewGroup.LayoutParams.MATCH_PARENT,
1208                ViewGroup.LayoutParams.MATCH_PARENT));
1209        mContentFrame.requestApplyInsets();
1210    }
1211
1212    void doOnHandleAssist(Bundle data, AssistStructure structure, Throwable failure,
1213            AssistContent content) {
1214        if (failure != null) {
1215            onAssistStructureFailure(failure);
1216        }
1217        onHandleAssist(data, structure, content);
1218    }
1219
1220    /**
1221     * Called when there has been a failure transferring the {@link AssistStructure} to
1222     * the assistant.  This may happen, for example, if the data is too large and results
1223     * in an out of memory exception, or the client has provided corrupt data.  This will
1224     * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied
1225     * there afterwards will be null.
1226     *
1227     * @param failure The failure exception that was thrown when building the
1228     * {@link AssistStructure}.
1229     */
1230    public void onAssistStructureFailure(Throwable failure) {
1231    }
1232
1233    /**
1234     * Called to receive data from the application that the user was currently viewing when
1235     * an assist session is started.  If the original show request did not specify
1236     * {@link #SHOW_WITH_ASSIST}, this method will not be called.
1237     *
1238     * @param data Arbitrary data supplied by the app through
1239     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
1240     * May be null if assist data has been disabled by the user or device policy.
1241     * @param structure If available, the structure definition of all windows currently
1242     * displayed by the app.  May be null if assist data has been disabled by the user
1243     * or device policy; will be an empty stub if the application has disabled assist
1244     * by marking its window as secure.
1245     * @param content Additional content data supplied by the app through
1246     * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
1247     * May be null if assist data has been disabled by the user or device policy; will
1248     * not be automatically filled in with data from the app if the app has marked its
1249     * window as secure.
1250     */
1251    public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure,
1252            @Nullable AssistContent content) {
1253    }
1254
1255    /**
1256     * Called to receive a screenshot of what the user was currently viewing when an assist
1257     * session is started.  May be null if screenshots are disabled by the user, policy,
1258     * or application.  If the original show request did not specify
1259     * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called.
1260     */
1261    public void onHandleScreenshot(@Nullable Bitmap screenshot) {
1262    }
1263
1264    public boolean onKeyDown(int keyCode, KeyEvent event) {
1265        return false;
1266    }
1267
1268    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
1269        return false;
1270    }
1271
1272    public boolean onKeyUp(int keyCode, KeyEvent event) {
1273        return false;
1274    }
1275
1276    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
1277        return false;
1278    }
1279
1280    /**
1281     * Called when the user presses the back button while focus is in the session UI.  Note
1282     * that this will only happen if the session UI has requested input focus in its window;
1283     * otherwise, the back key will go to whatever window has focus and do whatever behavior
1284     * it normally has there.  The default implementation simply calls {@link #hide}.
1285     */
1286    public void onBackPressed() {
1287        hide();
1288    }
1289
1290    /**
1291     * Sessions automatically watch for requests that all system UI be closed (such as when
1292     * the user presses HOME), which will appear here.  The default implementation always
1293     * calls {@link #hide}.
1294     */
1295    public void onCloseSystemDialogs() {
1296        hide();
1297    }
1298
1299    @Override
1300    public void onConfigurationChanged(Configuration newConfig) {
1301    }
1302
1303    @Override
1304    public void onLowMemory() {
1305    }
1306
1307    @Override
1308    public void onTrimMemory(int level) {
1309    }
1310
1311    /**
1312     * Compute the interesting insets into your UI.  The default implementation
1313     * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height
1314     * of the window, meaning it should not adjust content underneath.  The default touchable
1315     * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch
1316     * events within its window frame.
1317     *
1318     * @param outInsets Fill in with the current UI insets.
1319     */
1320    public void onComputeInsets(Insets outInsets) {
1321        outInsets.contentInsets.left = 0;
1322        outInsets.contentInsets.bottom = 0;
1323        outInsets.contentInsets.right = 0;
1324        View decor = getWindow().getWindow().getDecorView();
1325        outInsets.contentInsets.top = decor.getHeight();
1326        outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
1327        outInsets.touchableRegion.setEmpty();
1328    }
1329
1330    /**
1331     * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
1332     * has actually started.
1333     *
1334     * @param intent The original {@link Intent} supplied to
1335     * {@link #startVoiceActivity(android.content.Intent)}.
1336     * @param taskId Unique ID of the now running task.
1337     */
1338    public void onTaskStarted(Intent intent, int taskId) {
1339    }
1340
1341    /**
1342     * Called when the last activity of a task initiated by
1343     * {@link #startVoiceActivity(android.content.Intent)} has finished.  The default
1344     * implementation calls {@link #finish()} on the assumption that this represents
1345     * the completion of a voice action.  You can override the implementation if you would
1346     * like a different behavior.
1347     *
1348     * @param intent The original {@link Intent} supplied to
1349     * {@link #startVoiceActivity(android.content.Intent)}.
1350     * @param taskId Unique ID of the finished task.
1351     */
1352    public void onTaskFinished(Intent intent, int taskId) {
1353        hide();
1354    }
1355
1356    /**
1357     * Request to query for what extended commands the session supports.
1358     *
1359     * @param commands An array of commands that are being queried.
1360     * @return Return an array of booleans indicating which of each entry in the
1361     * command array is supported.  A true entry in the array indicates the command
1362     * is supported; false indicates it is not.  The default implementation returns
1363     * an array of all false entries.
1364     */
1365    public boolean[] onGetSupportedCommands(String[] commands) {
1366        return new boolean[commands.length];
1367    }
1368
1369    /**
1370     * Request to confirm with the user before proceeding with an unrecoverable operation,
1371     * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
1372     * VoiceInteractor.ConfirmationRequest}.
1373     *
1374     * @param request The active request.
1375     */
1376    public void onRequestConfirmation(ConfirmationRequest request) {
1377    }
1378
1379    /**
1380     * Request for the user to pick one of N options, corresponding to a
1381     * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}.
1382     *
1383     * @param request The active request.
1384     */
1385    public void onRequestPickOption(PickOptionRequest request) {
1386    }
1387
1388    /**
1389     * Request to complete the voice interaction session because the voice activity successfully
1390     * completed its interaction using voice.  Corresponds to
1391     * {@link android.app.VoiceInteractor.CompleteVoiceRequest
1392     * VoiceInteractor.CompleteVoiceRequest}.  The default implementation just sends an empty
1393     * confirmation back to allow the activity to exit.
1394     *
1395     * @param request The active request.
1396     */
1397    public void onRequestCompleteVoice(CompleteVoiceRequest request) {
1398    }
1399
1400    /**
1401     * Request to abort the voice interaction session because the voice activity can not
1402     * complete its interaction using voice.  Corresponds to
1403     * {@link android.app.VoiceInteractor.AbortVoiceRequest
1404     * VoiceInteractor.AbortVoiceRequest}.  The default implementation just sends an empty
1405     * confirmation back to allow the activity to exit.
1406     *
1407     * @param request The active request.
1408     */
1409    public void onRequestAbortVoice(AbortVoiceRequest request) {
1410    }
1411
1412    /**
1413     * Process an arbitrary extended command from the caller,
1414     * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
1415     * VoiceInteractor.CommandRequest}.
1416     *
1417     * @param request The active request.
1418     */
1419    public void onRequestCommand(CommandRequest request) {
1420    }
1421
1422    /**
1423     * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
1424     * that was previously delivered to {@link #onRequestConfirmation},
1425     * {@link #onRequestPickOption}, {@link #onRequestCompleteVoice}, {@link #onRequestAbortVoice},
1426     * or {@link #onRequestCommand}.
1427     *
1428     * @param request The request that is being canceled.
1429     */
1430    public void onCancelRequest(Request request) {
1431    }
1432}
1433