VoiceInteractionSessionConnection.java revision ffeecb1bfb9b71f4b62c9ef1fbf7b58a7a63f655
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.voiceinteraction; 18 19import android.app.ActivityManagerNative; 20import android.app.IActivityManager; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.os.Binder; 26import android.os.Bundle; 27import android.os.IBinder; 28import android.os.RemoteException; 29import android.os.ServiceManager; 30import android.os.UserHandle; 31import android.service.voice.IVoiceInteractionSession; 32import android.service.voice.IVoiceInteractionSessionService; 33import android.service.voice.VoiceInteractionService; 34import android.util.Slog; 35import android.view.IWindowManager; 36import android.view.WindowManager; 37import com.android.internal.app.IVoiceInteractor; 38import com.android.internal.os.IResultReceiver; 39 40import java.io.PrintWriter; 41 42final class VoiceInteractionSessionConnection implements ServiceConnection { 43 final static String TAG = "VoiceInteractionServiceManager"; 44 45 final IBinder mToken = new Binder(); 46 final Object mLock; 47 final ComponentName mSessionComponentName; 48 final Intent mBindIntent; 49 final int mUser; 50 final Context mContext; 51 final Callback mCallback; 52 final int mCallingPid; 53 final int mCallingUid; 54 final IActivityManager mAm; 55 final IWindowManager mIWindowManager; 56 boolean mShown; 57 Bundle mShowArgs; 58 int mShowFlags; 59 boolean mBound; 60 boolean mFullyBound; 61 boolean mCanceled; 62 IVoiceInteractionSessionService mService; 63 IVoiceInteractionSession mSession; 64 IVoiceInteractor mInteractor; 65 boolean mHaveAssistData; 66 Bundle mAssistData; 67 68 public interface Callback { 69 public void sessionConnectionGone(VoiceInteractionSessionConnection connection); 70 } 71 72 final ServiceConnection mFullConnection = new ServiceConnection() { 73 @Override 74 public void onServiceConnected(ComponentName name, IBinder service) { 75 } 76 @Override 77 public void onServiceDisconnected(ComponentName name) { 78 } 79 }; 80 81 final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() { 82 @Override 83 public void send(int resultCode, Bundle resultData) throws RemoteException { 84 synchronized (mLock) { 85 if (mShown) { 86 if (mSession != null) { 87 try { 88 mSession.handleAssist(resultData); 89 } catch (RemoteException e) { 90 } 91 } else { 92 mHaveAssistData = true; 93 mAssistData = resultData; 94 } 95 } 96 } 97 } 98 }; 99 100 public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user, 101 Context context, Callback callback, int callingPid, int callingUid) { 102 mLock = lock; 103 mSessionComponentName = component; 104 mUser = user; 105 mContext = context; 106 mCallback = callback; 107 mCallingPid = callingPid; 108 mCallingUid = callingUid; 109 mAm = ActivityManagerNative.getDefault(); 110 mIWindowManager = IWindowManager.Stub.asInterface( 111 ServiceManager.getService(Context.WINDOW_SERVICE)); 112 mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); 113 mBindIntent.setComponent(mSessionComponentName); 114 mBound = mContext.bindServiceAsUser(mBindIntent, this, 115 Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser)); 116 if (mBound) { 117 try { 118 mIWindowManager.addWindowToken(mToken, 119 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION); 120 } catch (RemoteException e) { 121 Slog.w(TAG, "Failed adding window token", e); 122 } 123 } else { 124 Slog.w(TAG, "Failed binding to voice interaction session service " 125 + mSessionComponentName); 126 } 127 } 128 129 public boolean showLocked(Bundle args, int flags) { 130 if (mBound) { 131 if (!mFullyBound) { 132 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, 133 Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY, 134 new UserHandle(mUser)); 135 } 136 mShown = true; 137 mShowArgs = args; 138 mShowFlags = flags; 139 if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) { 140 try { 141 mAm.requestAssistContextExtras(0, mAssistReceiver); 142 } catch (RemoteException e) { 143 } 144 } else { 145 mHaveAssistData = false; 146 mAssistData = null; 147 } 148 if (mSession != null) { 149 try { 150 mSession.show(mShowArgs, mShowFlags); 151 mShowArgs = null; 152 mShowFlags = 0; 153 } catch (RemoteException e) { 154 } 155 if (mHaveAssistData) { 156 try { 157 mSession.handleAssist(mAssistData); 158 mAssistData = null; 159 mHaveAssistData = false; 160 } catch (RemoteException e) { 161 } 162 } 163 } 164 return true; 165 } 166 return false; 167 } 168 169 public boolean hideLocked() { 170 if (mBound) { 171 if (mShown) { 172 mShown = false; 173 mShowArgs = null; 174 mShowFlags = 0; 175 mHaveAssistData = false; 176 mAssistData = null; 177 if (mSession != null) { 178 try { 179 mSession.hide(); 180 } catch (RemoteException e) { 181 } 182 } 183 } 184 if (mFullyBound) { 185 mContext.unbindService(mFullConnection); 186 mFullyBound = false; 187 } 188 return true; 189 } 190 return false; 191 } 192 193 public boolean deliverNewSessionLocked(IVoiceInteractionSession session, 194 IVoiceInteractor interactor) { 195 mSession = session; 196 mInteractor = interactor; 197 if (mShown) { 198 try { 199 session.show(mShowArgs, mShowFlags); 200 mShowArgs = null; 201 mShowFlags = 0; 202 } catch (RemoteException e) { 203 } 204 if (mHaveAssistData) { 205 try { 206 session.handleAssist(mAssistData); 207 mAssistData = null; 208 mHaveAssistData = false; 209 } catch (RemoteException e) { 210 } 211 } 212 } 213 return true; 214 } 215 216 @Override 217 public void onServiceConnected(ComponentName name, IBinder service) { 218 synchronized (mLock) { 219 mService = IVoiceInteractionSessionService.Stub.asInterface(service); 220 if (!mCanceled) { 221 try { 222 mService.newSession(mToken, mShowArgs, mShowFlags); 223 } catch (RemoteException e) { 224 Slog.w(TAG, "Failed adding window token", e); 225 } 226 } 227 } 228 } 229 230 @Override 231 public void onServiceDisconnected(ComponentName name) { 232 mCallback.sessionConnectionGone(this); 233 mService = null; 234 } 235 236 public void cancel() { 237 mCanceled = true; 238 if (mBound) { 239 if (mSession != null) { 240 try { 241 mSession.destroy(); 242 } catch (RemoteException e) { 243 Slog.w(TAG, "Voice interation session already dead"); 244 } 245 } 246 if (mSession != null) { 247 try { 248 mAm.finishVoiceTask(mSession); 249 } catch (RemoteException e) { 250 } 251 } 252 mContext.unbindService(this); 253 try { 254 mIWindowManager.removeWindowToken(mToken); 255 } catch (RemoteException e) { 256 Slog.w(TAG, "Failed removing window token", e); 257 } 258 mBound = false; 259 mService = null; 260 mSession = null; 261 mInteractor = null; 262 } 263 if (mFullyBound) { 264 mContext.unbindService(mFullConnection); 265 mFullyBound = false; 266 } 267 } 268 269 public void dump(String prefix, PrintWriter pw) { 270 pw.print(prefix); pw.print("mToken="); pw.println(mToken); 271 pw.print(prefix); pw.print("mShown="); pw.println(mShown); 272 pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs); 273 pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags)); 274 pw.print(prefix); pw.print("mBound="); pw.println(mBound); 275 if (mBound) { 276 pw.print(prefix); pw.print("mService="); pw.println(mService); 277 pw.print(prefix); pw.print("mSession="); pw.println(mSession); 278 pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor); 279 } 280 pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData); 281 if (mHaveAssistData) { 282 pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData); 283 } 284 } 285}; 286