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