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