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