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