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