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