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.SystemApi;
     20 import android.app.Dialog;
     21 import android.app.Instrumentation;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.res.TypedArray;
     25 import android.graphics.Rect;
     26 import android.graphics.Region;
     27 import android.inputmethodservice.SoftInputWindow;
     28 import android.os.Binder;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.Message;
     33 import android.os.RemoteException;
     34 import android.util.ArrayMap;
     35 import android.util.Log;
     36 import android.view.Gravity;
     37 import android.view.KeyEvent;
     38 import android.view.LayoutInflater;
     39 import android.view.View;
     40 import android.view.ViewGroup;
     41 import android.view.ViewTreeObserver;
     42 import android.view.WindowManager;
     43 import android.widget.FrameLayout;
     44 import com.android.internal.app.IVoiceInteractionManagerService;
     45 import com.android.internal.app.IVoiceInteractor;
     46 import com.android.internal.app.IVoiceInteractorCallback;
     47 import com.android.internal.app.IVoiceInteractorRequest;
     48 import com.android.internal.os.HandlerCaller;
     49 import com.android.internal.os.SomeArgs;
     50 
     51 import java.lang.ref.WeakReference;
     52 
     53 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     54 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
     55 
     56 /**
     57  * An active interaction session, started by a {@link VoiceInteractionService}.
     58  */
     59 public abstract class VoiceInteractionSession implements KeyEvent.Callback {
     60     static final String TAG = "VoiceInteractionSession";
     61     static final boolean DEBUG = true;
     62 
     63     final Context mContext;
     64     final HandlerCaller mHandlerCaller;
     65 
     66     final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
     67 
     68     IVoiceInteractionManagerService mSystemService;
     69     IBinder mToken;
     70 
     71     int mTheme = 0;
     72     LayoutInflater mInflater;
     73     TypedArray mThemeAttrs;
     74     View mRootView;
     75     FrameLayout mContentFrame;
     76     SoftInputWindow mWindow;
     77 
     78     boolean mInitialized;
     79     boolean mWindowAdded;
     80     boolean mWindowVisible;
     81     boolean mWindowWasVisible;
     82     boolean mInShowWindow;
     83 
     84     final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
     85 
     86     final Insets mTmpInsets = new Insets();
     87     final int[] mTmpLocation = new int[2];
     88 
     89     final WeakReference<VoiceInteractionSession> mWeakRef
     90             = new WeakReference<VoiceInteractionSession>(this);
     91 
     92     final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
     93         @Override
     94         public IVoiceInteractorRequest startConfirmation(String callingPackage,
     95                 IVoiceInteractorCallback callback, CharSequence prompt, Bundle extras) {
     96             Request request = newRequest(callback);
     97             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION,
     98                     new Caller(callingPackage, Binder.getCallingUid()), request,
     99                     prompt, extras));
    100             return request.mInterface;
    101         }
    102 
    103         @Override
    104         public IVoiceInteractorRequest startCompleteVoice(String callingPackage,
    105                 IVoiceInteractorCallback callback, CharSequence message, Bundle extras) {
    106             Request request = newRequest(callback);
    107             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMPLETE_VOICE,
    108                     new Caller(callingPackage, Binder.getCallingUid()), request,
    109                     message, extras));
    110             return request.mInterface;
    111         }
    112 
    113         @Override
    114         public IVoiceInteractorRequest startAbortVoice(String callingPackage,
    115                 IVoiceInteractorCallback callback, CharSequence message, Bundle extras) {
    116             Request request = newRequest(callback);
    117             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_ABORT_VOICE,
    118                     new Caller(callingPackage, Binder.getCallingUid()), request,
    119                     message, extras));
    120             return request.mInterface;
    121         }
    122 
    123         @Override
    124         public IVoiceInteractorRequest startCommand(String callingPackage,
    125                 IVoiceInteractorCallback callback, String command, Bundle extras) {
    126             Request request = newRequest(callback);
    127             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND,
    128                     new Caller(callingPackage, Binder.getCallingUid()), request,
    129                     command, extras));
    130             return request.mInterface;
    131         }
    132 
    133         @Override
    134         public boolean[] supportsCommands(String callingPackage, String[] commands) {
    135             Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
    136                     0, new Caller(callingPackage, Binder.getCallingUid()), commands);
    137             SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
    138             if (args != null) {
    139                 boolean[] res = (boolean[])args.arg1;
    140                 args.recycle();
    141                 return res;
    142             }
    143             return new boolean[commands.length];
    144         }
    145     };
    146 
    147     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
    148         @Override
    149         public void taskStarted(Intent intent, int taskId) {
    150             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
    151                     taskId, intent));
    152         }
    153 
    154         @Override
    155         public void taskFinished(Intent intent, int taskId) {
    156             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
    157                     taskId, intent));
    158         }
    159 
    160         @Override
    161         public void closeSystemDialogs() {
    162             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
    163         }
    164 
    165         @Override
    166         public void destroy() {
    167             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
    168         }
    169     };
    170 
    171     /**
    172      * @hide
    173      */
    174     @SystemApi
    175     public static class Request {
    176         final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
    177             @Override
    178             public void cancel() throws RemoteException {
    179                 VoiceInteractionSession session = mSession.get();
    180                 if (session != null) {
    181                     session.mHandlerCaller.sendMessage(
    182                             session.mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
    183                 }
    184             }
    185         };
    186         final IVoiceInteractorCallback mCallback;
    187         final WeakReference<VoiceInteractionSession> mSession;
    188 
    189         Request(IVoiceInteractorCallback callback, VoiceInteractionSession session) {
    190             mCallback = callback;
    191             mSession = session.mWeakRef;
    192         }
    193 
    194         void finishRequest() {
    195             VoiceInteractionSession session = mSession.get();
    196             if (session == null) {
    197                 throw new IllegalStateException("VoiceInteractionSession has been destroyed");
    198             }
    199             Request req = session.removeRequest(mInterface.asBinder());
    200             if (req == null) {
    201                 throw new IllegalStateException("Request not active: " + this);
    202             } else if (req != this) {
    203                 throw new IllegalStateException("Current active request " + req
    204                         + " not same as calling request " + this);
    205             }
    206         }
    207 
    208         public void sendConfirmResult(boolean confirmed, Bundle result) {
    209             try {
    210                 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
    211                         + " confirmed=" + confirmed + " result=" + result);
    212                 finishRequest();
    213                 mCallback.deliverConfirmationResult(mInterface, confirmed, result);
    214             } catch (RemoteException e) {
    215             }
    216         }
    217 
    218         public void sendCompleteVoiceResult(Bundle result) {
    219             try {
    220                 if (DEBUG) Log.d(TAG, "sendCompleteVoiceResult: req=" + mInterface
    221                         + " result=" + result);
    222                 finishRequest();
    223                 mCallback.deliverCompleteVoiceResult(mInterface, result);
    224             } catch (RemoteException e) {
    225             }
    226         }
    227 
    228         public void sendAbortVoiceResult(Bundle result) {
    229             try {
    230                 if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
    231                         + " result=" + result);
    232                 finishRequest();
    233                 mCallback.deliverAbortVoiceResult(mInterface, result);
    234             } catch (RemoteException e) {
    235             }
    236         }
    237 
    238         public void sendCommandResult(boolean complete, Bundle result) {
    239             try {
    240                 if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
    241                         + " result=" + result);
    242                 finishRequest();
    243                 mCallback.deliverCommandResult(mInterface, complete, result);
    244             } catch (RemoteException e) {
    245             }
    246         }
    247 
    248         public void sendCancelResult() {
    249             try {
    250                 if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
    251                 finishRequest();
    252                 mCallback.deliverCancel(mInterface);
    253             } catch (RemoteException e) {
    254             }
    255         }
    256     }
    257 
    258     /**
    259      * @hide
    260      */
    261     @SystemApi
    262     public static class Caller {
    263         final String packageName;
    264         final int uid;
    265 
    266         Caller(String _packageName, int _uid) {
    267             packageName = _packageName;
    268             uid = _uid;
    269         }
    270     }
    271 
    272     static final int MSG_START_CONFIRMATION = 1;
    273     static final int MSG_START_COMPLETE_VOICE = 2;
    274     static final int MSG_START_ABORT_VOICE = 3;
    275     static final int MSG_START_COMMAND = 4;
    276     static final int MSG_SUPPORTS_COMMANDS = 5;
    277     static final int MSG_CANCEL = 6;
    278 
    279     static final int MSG_TASK_STARTED = 100;
    280     static final int MSG_TASK_FINISHED = 101;
    281     static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
    282     static final int MSG_DESTROY = 103;
    283 
    284     class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
    285         @Override
    286         public void executeMessage(Message msg) {
    287             SomeArgs args;
    288             switch (msg.what) {
    289                 case MSG_START_CONFIRMATION:
    290                     args = (SomeArgs)msg.obj;
    291                     if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
    292                             + " prompt=" + args.arg3 + " extras=" + args.arg4);
    293                     onConfirm((Caller)args.arg1, (Request)args.arg2, (CharSequence)args.arg3,
    294                             (Bundle)args.arg4);
    295                     break;
    296                 case MSG_START_COMPLETE_VOICE:
    297                     args = (SomeArgs)msg.obj;
    298                     if (DEBUG) Log.d(TAG, "onCompleteVoice: req=" + ((Request) args.arg2).mInterface
    299                             + " message=" + args.arg3 + " extras=" + args.arg4);
    300                     onCompleteVoice((Caller) args.arg1, (Request) args.arg2,
    301                             (CharSequence) args.arg3, (Bundle) args.arg4);
    302                     break;
    303                 case MSG_START_ABORT_VOICE:
    304                     args = (SomeArgs)msg.obj;
    305                     if (DEBUG) Log.d(TAG, "onAbortVoice: req=" + ((Request) args.arg2).mInterface
    306                             + " message=" + args.arg3 + " extras=" + args.arg4);
    307                     onAbortVoice((Caller) args.arg1, (Request) args.arg2, (CharSequence) args.arg3,
    308                             (Bundle) args.arg4);
    309                     break;
    310                 case MSG_START_COMMAND:
    311                     args = (SomeArgs)msg.obj;
    312                     if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
    313                             + " command=" + args.arg3 + " extras=" + args.arg4);
    314                     onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
    315                             (Bundle) args.arg4);
    316                     break;
    317                 case MSG_SUPPORTS_COMMANDS:
    318                     args = (SomeArgs)msg.obj;
    319                     if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
    320                     args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
    321                     break;
    322                 case MSG_CANCEL:
    323                     args = (SomeArgs)msg.obj;
    324                     if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
    325                     onCancel((Request)args.arg1);
    326                     break;
    327                 case MSG_TASK_STARTED:
    328                     if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
    329                             + " taskId=" + msg.arg1);
    330                     onTaskStarted((Intent) msg.obj, msg.arg1);
    331                     break;
    332                 case MSG_TASK_FINISHED:
    333                     if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
    334                             + " taskId=" + msg.arg1);
    335                     onTaskFinished((Intent) msg.obj, msg.arg1);
    336                     break;
    337                 case MSG_CLOSE_SYSTEM_DIALOGS:
    338                     if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
    339                     onCloseSystemDialogs();
    340                     break;
    341                 case MSG_DESTROY:
    342                     if (DEBUG) Log.d(TAG, "doDestroy");
    343                     doDestroy();
    344                     break;
    345             }
    346         }
    347 
    348         @Override
    349         public void onBackPressed() {
    350             VoiceInteractionSession.this.onBackPressed();
    351         }
    352     }
    353 
    354     final MyCallbacks mCallbacks = new MyCallbacks();
    355 
    356     /**
    357      * @hide
    358      * Information about where interesting parts of the input method UI appear.
    359      */
    360     @SystemApi
    361     public static final class Insets {
    362         /**
    363          * This is the part of the UI that is the main content.  It is
    364          * used to determine the basic space needed, to resize/pan the
    365          * application behind.  It is assumed that this inset does not
    366          * change very much, since any change will cause a full resize/pan
    367          * of the application behind.  This value is relative to the top edge
    368          * of the input method window.
    369          */
    370         public final Rect contentInsets = new Rect();
    371 
    372         /**
    373          * This is the region of the UI that is touchable.  It is used when
    374          * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
    375          * The region should be specified relative to the origin of the window frame.
    376          */
    377         public final Region touchableRegion = new Region();
    378 
    379         /**
    380          * Option for {@link #touchableInsets}: the entire window frame
    381          * can be touched.
    382          */
    383         public static final int TOUCHABLE_INSETS_FRAME
    384                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
    385 
    386         /**
    387          * Option for {@link #touchableInsets}: the area inside of
    388          * the content insets can be touched.
    389          */
    390         public static final int TOUCHABLE_INSETS_CONTENT
    391                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
    392 
    393         /**
    394          * Option for {@link #touchableInsets}: the region specified by
    395          * {@link #touchableRegion} can be touched.
    396          */
    397         public static final int TOUCHABLE_INSETS_REGION
    398                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
    399 
    400         /**
    401          * Determine which area of the window is touchable by the user.  May
    402          * be one of: {@link #TOUCHABLE_INSETS_FRAME},
    403          * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
    404          */
    405         public int touchableInsets;
    406     }
    407 
    408     final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
    409             new ViewTreeObserver.OnComputeInternalInsetsListener() {
    410         public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
    411             onComputeInsets(mTmpInsets);
    412             info.contentInsets.set(mTmpInsets.contentInsets);
    413             info.visibleInsets.set(mTmpInsets.contentInsets);
    414             info.touchableRegion.set(mTmpInsets.touchableRegion);
    415             info.setTouchableInsets(mTmpInsets.touchableInsets);
    416         }
    417     };
    418 
    419     public VoiceInteractionSession(Context context) {
    420         this(context, new Handler());
    421     }
    422 
    423     public VoiceInteractionSession(Context context, Handler handler) {
    424         mContext = context;
    425         mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
    426                 mCallbacks, true);
    427     }
    428 
    429     Request newRequest(IVoiceInteractorCallback callback) {
    430         synchronized (this) {
    431             Request req = new Request(callback, this);
    432             mActiveRequests.put(req.mInterface.asBinder(), req);
    433             return req;
    434         }
    435     }
    436 
    437     Request removeRequest(IBinder reqInterface) {
    438         synchronized (this) {
    439             Request req = mActiveRequests.get(reqInterface);
    440             if (req != null) {
    441                 mActiveRequests.remove(req);
    442             }
    443             return req;
    444         }
    445     }
    446 
    447     void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
    448         mSystemService = service;
    449         mToken = token;
    450         onCreate(args);
    451     }
    452 
    453     void doDestroy() {
    454         onDestroy();
    455         if (mInitialized) {
    456             mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
    457                     mInsetsComputer);
    458             if (mWindowAdded) {
    459                 mWindow.dismiss();
    460                 mWindowAdded = false;
    461             }
    462             mInitialized = false;
    463         }
    464     }
    465 
    466     void initViews() {
    467         mInitialized = true;
    468 
    469         mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
    470         mRootView = mInflater.inflate(
    471                 com.android.internal.R.layout.voice_interaction_session, null);
    472         mRootView.setSystemUiVisibility(
    473                 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    474         mWindow.setContentView(mRootView);
    475         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
    476 
    477         mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
    478     }
    479 
    480     /**
    481      * @hide
    482      */
    483     @SystemApi
    484     public void showWindow() {
    485         if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
    486                 + " mWindowVisible=" + mWindowVisible);
    487 
    488         if (mInShowWindow) {
    489             Log.w(TAG, "Re-entrance in to showWindow");
    490             return;
    491         }
    492 
    493         try {
    494             mInShowWindow = true;
    495             if (!mWindowVisible) {
    496                 mWindowVisible = true;
    497                 if (!mWindowAdded) {
    498                     mWindowAdded = true;
    499                     View v = onCreateContentView();
    500                     if (v != null) {
    501                         setContentView(v);
    502                     }
    503                 }
    504                 mWindow.show();
    505             }
    506         } finally {
    507             mWindowWasVisible = true;
    508             mInShowWindow = false;
    509         }
    510     }
    511 
    512     /**
    513      * @hide
    514      */
    515     @SystemApi
    516     public void hideWindow() {
    517         if (mWindowVisible) {
    518             mWindow.hide();
    519             mWindowVisible = false;
    520         }
    521     }
    522 
    523     /**
    524      * @hide
    525      * You can call this to customize the theme used by your IME's window.
    526      * This must be set before {@link #onCreate}, so you
    527      * will typically call it in your constructor with the resource ID
    528      * of your custom theme.
    529      */
    530     @SystemApi
    531     public void setTheme(int theme) {
    532         if (mWindow != null) {
    533             throw new IllegalStateException("Must be called before onCreate()");
    534         }
    535         mTheme = theme;
    536     }
    537 
    538     /**
    539      * @hide
    540      * Ask that a new activity be started for voice interaction.  This will create a
    541      * new dedicated task in the activity manager for this voice interaction session;
    542      * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
    543      * will be set for you to make it a new task.
    544      *
    545      * <p>The newly started activity will be displayed to the user in a special way, as
    546      * a layer under the voice interaction UI.</p>
    547      *
    548      * <p>As the voice activity runs, it can retrieve a {@link android.app.VoiceInteractor}
    549      * through which it can perform voice interactions through your session.  These requests
    550      * for voice interactions will appear as callbacks on {@link #onGetSupportedCommands},
    551      * {@link #onConfirm}, {@link #onCommand}, and {@link #onCancel}.
    552      *
    553      * <p>You will receive a call to {@link #onTaskStarted} when the task starts up
    554      * and {@link #onTaskFinished} when the last activity has finished.
    555      *
    556      * @param intent The Intent to start this voice interaction.  The given Intent will
    557      * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
    558      * this is part of a voice interaction.
    559      */
    560     @SystemApi
    561     public void startVoiceActivity(Intent intent) {
    562         if (mToken == null) {
    563             throw new IllegalStateException("Can't call before onCreate()");
    564         }
    565         try {
    566             intent.migrateExtraStreamToClipData();
    567             intent.prepareToLeaveProcess();
    568             int res = mSystemService.startVoiceActivity(mToken, intent,
    569                     intent.resolveType(mContext.getContentResolver()));
    570             Instrumentation.checkStartActivityResult(res, intent);
    571         } catch (RemoteException e) {
    572         }
    573     }
    574 
    575     /**
    576      * @hide
    577      * Convenience for inflating views.
    578      */
    579     @SystemApi
    580     public LayoutInflater getLayoutInflater() {
    581         return mInflater;
    582     }
    583 
    584     /**
    585      * @hide
    586      * Retrieve the window being used to show the session's UI.
    587      */
    588     @SystemApi
    589     public Dialog getWindow() {
    590         return mWindow;
    591     }
    592 
    593     /**
    594      * Finish the session.
    595      */
    596     public void finish() {
    597         if (mToken == null) {
    598             throw new IllegalStateException("Can't call before onCreate()");
    599         }
    600         hideWindow();
    601         try {
    602             mSystemService.finish(mToken);
    603         } catch (RemoteException e) {
    604         }
    605     }
    606 
    607     /**
    608      * Initiatize a new session.
    609      *
    610      * @param args The arguments that were supplied to
    611      * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
    612      */
    613     public void onCreate(Bundle args) {
    614         mTheme = mTheme != 0 ? mTheme
    615                 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
    616         mInflater = (LayoutInflater)mContext.getSystemService(
    617                 Context.LAYOUT_INFLATER_SERVICE);
    618         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
    619                 mCallbacks, this, mDispatcherState,
    620                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true);
    621         mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
    622         initViews();
    623         mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
    624         mWindow.setToken(mToken);
    625     }
    626 
    627     /**
    628      * Last callback to the session as it is being finished.
    629      */
    630     public void onDestroy() {
    631     }
    632 
    633     /**
    634      * @hide
    635      * Hook in which to create the session's UI.
    636      */
    637     @SystemApi
    638     public View onCreateContentView() {
    639         return null;
    640     }
    641 
    642     public void setContentView(View view) {
    643         mContentFrame.removeAllViews();
    644         mContentFrame.addView(view, new FrameLayout.LayoutParams(
    645                 ViewGroup.LayoutParams.MATCH_PARENT,
    646                 ViewGroup.LayoutParams.WRAP_CONTENT));
    647 
    648     }
    649 
    650     /**
    651      * @hide
    652      */
    653     @SystemApi
    654     public boolean onKeyDown(int keyCode, KeyEvent event) {
    655         return false;
    656     }
    657 
    658     /**
    659      * @hide
    660      */
    661     @SystemApi
    662     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
    663         return false;
    664     }
    665 
    666     /**
    667      * @hide
    668      */
    669     @SystemApi
    670     public boolean onKeyUp(int keyCode, KeyEvent event) {
    671         return false;
    672     }
    673 
    674     /**
    675      * @hide
    676      */
    677     @SystemApi
    678     public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
    679         return false;
    680     }
    681 
    682     /**
    683      * @hide
    684      */
    685     @SystemApi
    686     public void onBackPressed() {
    687         finish();
    688     }
    689 
    690     /**
    691      * Sessions automatically watch for requests that all system UI be closed (such as when
    692      * the user presses HOME), which will appear here.  The default implementation always
    693      * calls {@link #finish}.
    694      */
    695     public void onCloseSystemDialogs() {
    696         finish();
    697     }
    698 
    699     /**
    700      * @hide
    701      * Compute the interesting insets into your UI.  The default implementation
    702      * uses the entire window frame as the insets.  The default touchable
    703      * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
    704      *
    705      * @param outInsets Fill in with the current UI insets.
    706      */
    707     @SystemApi
    708     public void onComputeInsets(Insets outInsets) {
    709         int[] loc = mTmpLocation;
    710         View decor = getWindow().getWindow().getDecorView();
    711         decor.getLocationInWindow(loc);
    712         outInsets.contentInsets.top = 0;
    713         outInsets.contentInsets.left = 0;
    714         outInsets.contentInsets.right = 0;
    715         outInsets.contentInsets.bottom = 0;
    716         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
    717         outInsets.touchableRegion.setEmpty();
    718     }
    719 
    720     /**
    721      * @hide
    722      * @SystemApi
    723      * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
    724      * has actually started.
    725      *
    726      * @param intent The original {@link Intent} supplied to
    727      * {@link #startVoiceActivity(android.content.Intent)}.
    728      * @param taskId Unique ID of the now running task.
    729      */
    730     public void onTaskStarted(Intent intent, int taskId) {
    731     }
    732 
    733     /**
    734      * @hide
    735      * @SystemApi
    736      * Called when the last activity of a task initiated by
    737      * {@link #startVoiceActivity(android.content.Intent)} has finished.  The default
    738      * implementation calls {@link #finish()} on the assumption that this represents
    739      * the completion of a voice action.  You can override the implementation if you would
    740      * like a different behavior.
    741      *
    742      * @param intent The original {@link Intent} supplied to
    743      * {@link #startVoiceActivity(android.content.Intent)}.
    744      * @param taskId Unique ID of the finished task.
    745      */
    746     public void onTaskFinished(Intent intent, int taskId) {
    747         finish();
    748     }
    749 
    750     /**
    751      * @hide
    752      * @SystemApi
    753      * Request to query for what extended commands the session supports.
    754      *
    755      * @param caller Who is making the request.
    756      * @param commands An array of commands that are being queried.
    757      * @return Return an array of booleans indicating which of each entry in the
    758      * command array is supported.  A true entry in the array indicates the command
    759      * is supported; false indicates it is not.  The default implementation returns
    760      * an array of all false entries.
    761      */
    762     public boolean[] onGetSupportedCommands(Caller caller, String[] commands) {
    763         return new boolean[commands.length];
    764     }
    765 
    766     /**
    767      * @hide
    768      * @SystemApi
    769      * Request to confirm with the user before proceeding with an unrecoverable operation,
    770      * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
    771      * VoiceInteractor.ConfirmationRequest}.
    772      *
    773      * @param caller Who is making the request.
    774      * @param request The active request.
    775      * @param prompt The prompt informing the user of what will happen, as per
    776      * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}.
    777      * @param extras Any additional information, as per
    778      * {@link android.app.VoiceInteractor.ConfirmationRequest VoiceInteractor.ConfirmationRequest}.
    779      */
    780     public abstract void onConfirm(Caller caller, Request request, CharSequence prompt,
    781             Bundle extras);
    782 
    783     /**
    784      * @hide
    785      * @SystemApi
    786      * Request to complete the voice interaction session because the voice activity successfully
    787      * completed its interaction using voice.  Corresponds to
    788      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
    789      * VoiceInteractor.CompleteVoiceRequest}.  The default implementation just sends an empty
    790      * confirmation back to allow the activity to exit.
    791      *
    792      * @param caller Who is making the request.
    793      * @param request The active request.
    794      * @param message The message informing the user of the problem, as per
    795      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
    796      * VoiceInteractor.CompleteVoiceRequest}.
    797      * @param extras Any additional information, as per
    798      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
    799      * VoiceInteractor.CompleteVoiceRequest}.
    800      */
    801     public void onCompleteVoice(Caller caller, Request request, CharSequence message,
    802            Bundle extras) {
    803         request.sendCompleteVoiceResult(null);
    804     }
    805 
    806     /**
    807      * @hide
    808      * @SystemApi
    809      * Request to abort the voice interaction session because the voice activity can not
    810      * complete its interaction using voice.  Corresponds to
    811      * {@link android.app.VoiceInteractor.AbortVoiceRequest
    812      * VoiceInteractor.AbortVoiceRequest}.  The default implementation just sends an empty
    813      * confirmation back to allow the activity to exit.
    814      *
    815      * @param caller Who is making the request.
    816      * @param request The active request.
    817      * @param message The message informing the user of the problem, as per
    818      * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
    819      * @param extras Any additional information, as per
    820      * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}.
    821      */
    822     public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) {
    823         request.sendAbortVoiceResult(null);
    824     }
    825 
    826     /**
    827      * @hide
    828      * @SystemApi
    829      * Process an arbitrary extended command from the caller,
    830      * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
    831      * VoiceInteractor.CommandRequest}.
    832      *
    833      * @param caller Who is making the request.
    834      * @param request The active request.
    835      * @param command The command that is being executed, as per
    836      * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
    837      * @param extras Any additional information, as per
    838      * {@link android.app.VoiceInteractor.CommandRequest VoiceInteractor.CommandRequest}.
    839      */
    840     public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
    841 
    842     /**
    843      * @hide
    844      * @SystemApi
    845      * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
    846      * that was previously delivered to {@link #onConfirm} or {@link #onCommand}.
    847      *
    848      * @param request The request that is being canceled.
    849      */
    850     public abstract void onCancel(Request request);
    851 }
    852