109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley/* 209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * Copyright (C) 2015 The Android Open Source Project 309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * 409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License"); 509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * you may not use this file except in compliance with the License. 609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * You may obtain a copy of the License at 709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * 809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * http://www.apache.org/licenses/LICENSE-2.0 909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * 1009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * Unless required by applicable law or agreed to in writing, software 1109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS, 1209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * See the License for the specific language governing permissions and 1409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley * limitations under the License. 1509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley */ 1609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 1709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileypackage com.android.server.voiceinteraction; 1809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 1909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.app.ActivityManager; 2009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.app.ActivityManagerNative; 2109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.app.AppOpsManager; 22cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.app.IActivityManager; 23cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.app.assist.AssistContent; 24cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.app.assist.AssistStructure; 25cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.content.ClipData; 26cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.content.ComponentName; 27c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.content.ContentProvider; 28cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.content.Context; 29cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.content.Intent; 30cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.content.ServiceConnection; 31cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport android.graphics.Bitmap; 32c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.net.Uri; 33c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.Binder; 34c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.Bundle; 35c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.Handler; 36c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.IBinder; 37c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.RemoteException; 38c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.ServiceManager; 39c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.os.UserHandle; 40c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.provider.Settings; 41c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport android.service.voice.IVoiceInteractionSession; 4209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.service.voice.IVoiceInteractionSessionService; 4309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.service.voice.VoiceInteractionService; 4409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.service.voice.VoiceInteractionSession; 4509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.util.Slog; 4609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.view.IWindowManager; 4709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport android.view.WindowManager; 4809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 4909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport com.android.internal.app.IAssistScreenshotReceiver; 50c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport com.android.internal.app.IVoiceInteractionSessionShowCallback; 51cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wileyimport com.android.internal.app.IVoiceInteractor; 52c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport com.android.internal.logging.MetricsLogger; 53c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport com.android.internal.os.IResultReceiver; 54c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport com.android.server.LocalServices; 55c1e491d5a4923298b612de919537d4293574b443Christopher Wileyimport com.android.server.statusbar.StatusBarManagerInternal; 56c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 5709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport java.io.PrintWriter; 5809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport java.util.ArrayList; 5909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyimport java.util.List; 6009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 6109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wileyfinal class VoiceInteractionSessionConnection implements ServiceConnection { 6209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 6309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final static String TAG = "VoiceInteractionServiceManager"; 6409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 6509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley private static final String KEY_RECEIVER_EXTRA_COUNT = "count"; 6609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley private static final String KEY_RECEIVER_EXTRA_INDEX = "index"; 6709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 6809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final IBinder mToken = new Binder(); 6909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final Object mLock; 7009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final ComponentName mSessionComponentName; 7109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final Intent mBindIntent; 7209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final int mUser; 7309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final Context mContext; 7409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final Callback mCallback; 7509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final int mCallingUid; 7609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final Handler mHandler; 7709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final IActivityManager mAm; 7809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final IWindowManager mIWindowManager; 7909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final AppOpsManager mAppOps; 8009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final IBinder mPermissionOwner; 8109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley boolean mShown; 8209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley Bundle mShowArgs; 8309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley int mShowFlags; 8409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley boolean mBound; 8509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley boolean mFullyBound; 8609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley boolean mCanceled; 87cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley IVoiceInteractionSessionService mService; 88cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley IVoiceInteractionSession mSession; 89cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley IVoiceInteractor mInteractor; 90cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley boolean mHaveAssistData; 91cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley int mPendingAssistDataCount; 92cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley ArrayList<AssistDataForActivity> mAssistData = new ArrayList<>(); 93cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley boolean mHaveScreenshot; 9409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley Bitmap mScreenshot; 95c1e491d5a4923298b612de919537d4293574b443Christopher Wiley ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>(); 96c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 97c1e491d5a4923298b612de919537d4293574b443Christopher Wiley static class AssistDataForActivity { 98c1e491d5a4923298b612de919537d4293574b443Christopher Wiley int activityIndex; 99c1e491d5a4923298b612de919537d4293574b443Christopher Wiley int activityCount; 100c1e491d5a4923298b612de919537d4293574b443Christopher Wiley Bundle data; 101c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 102c1e491d5a4923298b612de919537d4293574b443Christopher Wiley public AssistDataForActivity(Bundle data) { 10309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley this.data = data; 10409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley Bundle receiverExtras = data.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS); 10509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley if (receiverExtras != null) { 10609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX); 107cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT); 108cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley } 109cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley } 110cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley } 111cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley 112cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley IVoiceInteractionSessionShowCallback mShowCallback = 11309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley new IVoiceInteractionSessionShowCallback.Stub() { 11409eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley @Override 11509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley public void onFailed() throws RemoteException { 11609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley synchronized (mLock) { 11709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley notifyPendingShowCallbacksFailedLocked(); 11809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley } 11909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley } 120c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 121c1e491d5a4923298b612de919537d4293574b443Christopher Wiley @Override 122c1e491d5a4923298b612de919537d4293574b443Christopher Wiley public void onShown() throws RemoteException { 123c1e491d5a4923298b612de919537d4293574b443Christopher Wiley synchronized (mLock) { 124c1e491d5a4923298b612de919537d4293574b443Christopher Wiley // TODO: Figure out whether this is good enough or whether we need to hook into 12509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley // Window manager to actually wait for the window to be drawn. 12609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley notifyPendingShowCallbacksShownLocked(); 12709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley } 12809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley } 12909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley }; 130cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley 13109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley public interface Callback { 13209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley public void sessionConnectionGone(VoiceInteractionSessionConnection connection); 13309eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley } 134c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 135c1e491d5a4923298b612de919537d4293574b443Christopher Wiley final ServiceConnection mFullConnection = new ServiceConnection() { 136c1e491d5a4923298b612de919537d4293574b443Christopher Wiley @Override 137c1e491d5a4923298b612de919537d4293574b443Christopher Wiley public void onServiceConnected(ComponentName name, IBinder service) { 138c1e491d5a4923298b612de919537d4293574b443Christopher Wiley } 139c1e491d5a4923298b612de919537d4293574b443Christopher Wiley @Override 140c1e491d5a4923298b612de919537d4293574b443Christopher Wiley public void onServiceDisconnected(ComponentName name) { 141c1e491d5a4923298b612de919537d4293574b443Christopher Wiley } 142c1e491d5a4923298b612de919537d4293574b443Christopher Wiley }; 143c1e491d5a4923298b612de919537d4293574b443Christopher Wiley 144c1e491d5a4923298b612de919537d4293574b443Christopher Wiley final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() { 14509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley @Override 14609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley public void send(int resultCode, Bundle resultData) throws RemoteException { 14709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley synchronized (mLock) { 14809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley if (mShown) { 14909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley mHaveAssistData = true; 15009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley mAssistData.add(new AssistDataForActivity(resultData)); 151c1e491d5a4923298b612de919537d4293574b443Christopher Wiley deliverSessionDataLocked(); 152c1e491d5a4923298b612de919537d4293574b443Christopher Wiley } 153cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley } 154cff7f175c1a4f790fdc64a56695c5b4b08b6bb6eChristopher Wiley } 15509eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley }; 15609eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley 15709eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley final IAssistScreenshotReceiver mScreenshotReceiver = new IAssistScreenshotReceiver.Stub() { 15809eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley @Override 15909eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley public void send(Bitmap screenshot) throws RemoteException { 16009eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley synchronized (mLock) { 16109eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley if (mShown) { 16209eb749704afd9e226e1347cb20c90be2016cd21Christopher Wiley mHaveScreenshot = true; 163 mScreenshot = screenshot; 164 deliverSessionDataLocked(); 165 } 166 } 167 } 168 }; 169 170 public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user, 171 Context context, Callback callback, int callingUid, Handler handler) { 172 mLock = lock; 173 mSessionComponentName = component; 174 mUser = user; 175 mContext = context; 176 mCallback = callback; 177 mCallingUid = callingUid; 178 mHandler = handler; 179 mAm = ActivityManagerNative.getDefault(); 180 mIWindowManager = IWindowManager.Stub.asInterface( 181 ServiceManager.getService(Context.WINDOW_SERVICE)); 182 mAppOps = context.getSystemService(AppOpsManager.class); 183 IBinder permOwner = null; 184 try { 185 permOwner = mAm.newUriPermissionOwner("voicesession:" 186 + component.flattenToShortString()); 187 } catch (RemoteException e) { 188 Slog.w("voicesession", "AM dead", e); 189 } 190 mPermissionOwner = permOwner; 191 mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); 192 mBindIntent.setComponent(mSessionComponentName); 193 mBound = mContext.bindServiceAsUser(mBindIntent, this, 194 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY 195 | Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser)); 196 if (mBound) { 197 try { 198 mIWindowManager.addWindowToken(mToken, 199 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION); 200 } catch (RemoteException e) { 201 Slog.w(TAG, "Failed adding window token", e); 202 } 203 } else { 204 Slog.w(TAG, "Failed binding to voice interaction session service " 205 + mSessionComponentName); 206 } 207 } 208 209 public int getUserDisabledShowContextLocked() { 210 int flags = 0; 211 if (Settings.Secure.getIntForUser(mContext.getContentResolver(), 212 Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) == 0) { 213 flags |= VoiceInteractionSession.SHOW_WITH_ASSIST; 214 } 215 if (Settings.Secure.getIntForUser(mContext.getContentResolver(), 216 Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) == 0) { 217 flags |= VoiceInteractionSession.SHOW_WITH_SCREENSHOT; 218 } 219 return flags; 220 } 221 222 public boolean showLocked(Bundle args, int flags, int disabledContext, 223 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken, 224 List<IBinder> topActivities) { 225 if (mBound) { 226 if (!mFullyBound) { 227 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, 228 Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY 229 | Context.BIND_FOREGROUND_SERVICE, 230 new UserHandle(mUser)); 231 } 232 mShown = true; 233 boolean isAssistDataAllowed = true; 234 try { 235 isAssistDataAllowed = mAm.isAssistDataAllowedOnCurrentActivity(); 236 } catch (RemoteException e) { 237 } 238 disabledContext |= getUserDisabledShowContextLocked(); 239 boolean structureEnabled = isAssistDataAllowed 240 && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0; 241 boolean screenshotEnabled = isAssistDataAllowed && structureEnabled 242 && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0; 243 mShowArgs = args; 244 mShowFlags = flags; 245 mHaveAssistData = false; 246 mPendingAssistDataCount = 0; 247 boolean needDisclosure = false; 248 if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) { 249 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid, 250 mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED 251 && structureEnabled) { 252 mAssistData.clear(); 253 final int count = activityToken != null ? 1 : topActivities.size(); 254 // Temp workaround for bug: 28348867 Revert after DP3 255 for (int i = 0; i < count && i < 1; i++) { 256 IBinder topActivity = count == 1 ? activityToken : topActivities.get(i); 257 try { 258 MetricsLogger.count(mContext, "assist_with_context", 1); 259 Bundle receiverExtras = new Bundle(); 260 receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i); 261 receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, count); 262 if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, 263 mAssistReceiver, receiverExtras, topActivity, 264 /* focused= */ i == 0, /* newSessionId= */ i == 0)) { 265 needDisclosure = true; 266 mPendingAssistDataCount++; 267 } else if (i == 0) { 268 // Wasn't allowed... given that, let's not do the screenshot either. 269 mHaveAssistData = true; 270 mAssistData.clear(); 271 screenshotEnabled = false; 272 break; 273 } 274 } catch (RemoteException e) { 275 } 276 } 277 } else { 278 mHaveAssistData = true; 279 mAssistData.clear(); 280 } 281 } else { 282 mAssistData.clear(); 283 } 284 mHaveScreenshot = false; 285 if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) { 286 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid, 287 mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED 288 && screenshotEnabled) { 289 try { 290 MetricsLogger.count(mContext, "assist_with_screen", 1); 291 needDisclosure = true; 292 mIWindowManager.requestAssistScreenshot(mScreenshotReceiver); 293 } catch (RemoteException e) { 294 } 295 } else { 296 mHaveScreenshot = true; 297 mScreenshot = null; 298 } 299 } else { 300 mScreenshot = null; 301 } 302 if (needDisclosure) { 303 mHandler.post(mShowAssistDisclosureRunnable); 304 } 305 if (mSession != null) { 306 try { 307 mSession.show(mShowArgs, mShowFlags, showCallback); 308 mShowArgs = null; 309 mShowFlags = 0; 310 } catch (RemoteException e) { 311 } 312 deliverSessionDataLocked(); 313 } else if (showCallback != null) { 314 mPendingShowCallbacks.add(showCallback); 315 } 316 return true; 317 } 318 if (showCallback != null) { 319 try { 320 showCallback.onFailed(); 321 } catch (RemoteException e) { 322 } 323 } 324 return false; 325 } 326 327 void grantUriPermission(Uri uri, int mode, int srcUid, int destUid, String destPkg) { 328 if (!"content".equals(uri.getScheme())) { 329 return; 330 } 331 long ident = Binder.clearCallingIdentity(); 332 try { 333 // This will throw SecurityException for us. 334 mAm.checkGrantUriPermission(srcUid, null, ContentProvider.getUriWithoutUserId(uri), 335 mode, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(srcUid))); 336 // No security exception, do the grant. 337 int sourceUserId = ContentProvider.getUserIdFromUri(uri, mUser); 338 uri = ContentProvider.getUriWithoutUserId(uri); 339 mAm.grantUriPermissionFromOwner(mPermissionOwner, srcUid, destPkg, 340 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, mUser); 341 } catch (RemoteException e) { 342 } catch (SecurityException e) { 343 Slog.w(TAG, "Can't propagate permission", e); 344 } finally { 345 Binder.restoreCallingIdentity(ident); 346 } 347 348 } 349 350 void grantClipDataItemPermission(ClipData.Item item, int mode, int srcUid, int destUid, 351 String destPkg) { 352 if (item.getUri() != null) { 353 grantUriPermission(item.getUri(), mode, srcUid, destUid, destPkg); 354 } 355 Intent intent = item.getIntent(); 356 if (intent != null && intent.getData() != null) { 357 grantUriPermission(intent.getData(), mode, srcUid, destUid, destPkg); 358 } 359 } 360 361 void grantClipDataPermissions(ClipData data, int mode, int srcUid, int destUid, 362 String destPkg) { 363 final int N = data.getItemCount(); 364 for (int i=0; i<N; i++) { 365 grantClipDataItemPermission(data.getItemAt(i), mode, srcUid, destUid, destPkg); 366 } 367 } 368 369 void deliverSessionDataLocked() { 370 if (mSession == null) { 371 return; 372 } 373 if (mHaveAssistData) { 374 AssistDataForActivity assistData; 375 if (mAssistData.isEmpty()) { 376 // We're not actually going to get any data, deliver some nothing 377 try { 378 mSession.handleAssist(null, null, null, 0, 0); 379 } catch (RemoteException e) { 380 } 381 } else { 382 while (!mAssistData.isEmpty()) { 383 if (mPendingAssistDataCount <= 0) { 384 Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount); 385 } 386 mPendingAssistDataCount--; 387 assistData = mAssistData.remove(0); 388 if (assistData.data == null) { 389 try { 390 mSession.handleAssist(null, null, null, assistData.activityIndex, 391 assistData.activityCount); 392 } catch (RemoteException e) { 393 } 394 } else { 395 deliverSessionDataLocked(assistData); 396 } 397 } 398 } 399 if (mPendingAssistDataCount <= 0) { 400 mHaveAssistData = false; 401 } // else, more to come 402 } 403 if (mHaveScreenshot) { 404 try { 405 mSession.handleScreenshot(mScreenshot); 406 } catch (RemoteException e) { 407 } 408 mScreenshot = null; 409 mHaveScreenshot = false; 410 } 411 } 412 413 private void deliverSessionDataLocked(AssistDataForActivity assistDataForActivity) { 414 Bundle assistData = assistDataForActivity.data.getBundle( 415 VoiceInteractionSession.KEY_DATA); 416 AssistStructure structure = assistDataForActivity.data.getParcelable( 417 VoiceInteractionSession.KEY_STRUCTURE); 418 AssistContent content = assistDataForActivity.data.getParcelable( 419 VoiceInteractionSession.KEY_CONTENT); 420 int uid = assistDataForActivity.data.getInt(Intent.EXTRA_ASSIST_UID, -1); 421 if (uid >= 0 && content != null) { 422 Intent intent = content.getIntent(); 423 if (intent != null) { 424 ClipData data = intent.getClipData(); 425 if (data != null && Intent.isAccessUriMode(intent.getFlags())) { 426 grantClipDataPermissions(data, intent.getFlags(), uid, 427 mCallingUid, mSessionComponentName.getPackageName()); 428 } 429 } 430 ClipData data = content.getClipData(); 431 if (data != null) { 432 grantClipDataPermissions(data, 433 Intent.FLAG_GRANT_READ_URI_PERMISSION, 434 uid, mCallingUid, mSessionComponentName.getPackageName()); 435 } 436 } 437 try { 438 mSession.handleAssist(assistData, structure, content, 439 assistDataForActivity.activityIndex, assistDataForActivity.activityCount); 440 } catch (RemoteException e) { 441 } 442 } 443 444 public boolean hideLocked() { 445 if (mBound) { 446 if (mShown) { 447 mShown = false; 448 mShowArgs = null; 449 mShowFlags = 0; 450 mHaveAssistData = false; 451 mAssistData.clear(); 452 if (mSession != null) { 453 try { 454 mSession.hide(); 455 } catch (RemoteException e) { 456 } 457 } 458 try { 459 mAm.revokeUriPermissionFromOwner(mPermissionOwner, null, 460 Intent.FLAG_GRANT_READ_URI_PERMISSION 461 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 462 mUser); 463 } catch (RemoteException e) { 464 } 465 if (mSession != null) { 466 try { 467 mAm.finishVoiceTask(mSession); 468 } catch (RemoteException e) { 469 } 470 } 471 } 472 if (mFullyBound) { 473 mContext.unbindService(mFullConnection); 474 mFullyBound = false; 475 } 476 return true; 477 } 478 return false; 479 } 480 481 public void cancelLocked(boolean finishTask) { 482 hideLocked(); 483 mCanceled = true; 484 if (mBound) { 485 if (mSession != null) { 486 try { 487 mSession.destroy(); 488 } catch (RemoteException e) { 489 Slog.w(TAG, "Voice interation session already dead"); 490 } 491 } 492 if (finishTask && mSession != null) { 493 try { 494 mAm.finishVoiceTask(mSession); 495 } catch (RemoteException e) { 496 } 497 } 498 mContext.unbindService(this); 499 try { 500 mIWindowManager.removeWindowToken(mToken); 501 } catch (RemoteException e) { 502 Slog.w(TAG, "Failed removing window token", e); 503 } 504 mBound = false; 505 mService = null; 506 mSession = null; 507 mInteractor = null; 508 } 509 if (mFullyBound) { 510 mContext.unbindService(mFullConnection); 511 mFullyBound = false; 512 } 513 } 514 515 public boolean deliverNewSessionLocked(IVoiceInteractionSession session, 516 IVoiceInteractor interactor) { 517 mSession = session; 518 mInteractor = interactor; 519 if (mShown) { 520 try { 521 session.show(mShowArgs, mShowFlags, mShowCallback); 522 mShowArgs = null; 523 mShowFlags = 0; 524 } catch (RemoteException e) { 525 } 526 deliverSessionDataLocked(); 527 } 528 return true; 529 } 530 531 private void notifyPendingShowCallbacksShownLocked() { 532 for (int i = 0; i < mPendingShowCallbacks.size(); i++) { 533 try { 534 mPendingShowCallbacks.get(i).onShown(); 535 } catch (RemoteException e) { 536 } 537 } 538 mPendingShowCallbacks.clear(); 539 } 540 541 private void notifyPendingShowCallbacksFailedLocked() { 542 for (int i = 0; i < mPendingShowCallbacks.size(); i++) { 543 try { 544 mPendingShowCallbacks.get(i).onFailed(); 545 } catch (RemoteException e) { 546 } 547 } 548 mPendingShowCallbacks.clear(); 549 } 550 551 @Override 552 public void onServiceConnected(ComponentName name, IBinder service) { 553 synchronized (mLock) { 554 mService = IVoiceInteractionSessionService.Stub.asInterface(service); 555 if (!mCanceled) { 556 try { 557 mService.newSession(mToken, mShowArgs, mShowFlags); 558 } catch (RemoteException e) { 559 Slog.w(TAG, "Failed adding window token", e); 560 } 561 } 562 } 563 } 564 565 @Override 566 public void onServiceDisconnected(ComponentName name) { 567 mCallback.sessionConnectionGone(this); 568 mService = null; 569 } 570 571 public void dump(String prefix, PrintWriter pw) { 572 pw.print(prefix); pw.print("mToken="); pw.println(mToken); 573 pw.print(prefix); pw.print("mShown="); pw.println(mShown); 574 pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs); 575 pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags)); 576 pw.print(prefix); pw.print("mBound="); pw.println(mBound); 577 if (mBound) { 578 pw.print(prefix); pw.print("mService="); pw.println(mService); 579 pw.print(prefix); pw.print("mSession="); pw.println(mSession); 580 pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor); 581 } 582 pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData); 583 if (mHaveAssistData) { 584 pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData); 585 } 586 } 587 588 private Runnable mShowAssistDisclosureRunnable = new Runnable() { 589 @Override 590 public void run() { 591 StatusBarManagerInternal statusBarInternal = LocalServices.getService( 592 StatusBarManagerInternal.class); 593 if (statusBarInternal != null) { 594 statusBarInternal.showAssistDisclosure(); 595 } 596 } 597 }; 598}; 599