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