diff options
author | Dianne Hackborn <hackbod@google.com> | 2015-03-11 15:16:13 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2015-03-12 17:07:51 -0700 |
commit | a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9d (patch) | |
tree | 2b0f1d1e65920fdbf7e3b7867070ee32776f246e /services/voiceinteraction | |
parent | d6ee06a0c86d9d1556bb4b15c9aaea538e415e38 (diff) | |
download | frameworks_base-a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9d.zip frameworks_base-a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9d.tar.gz frameworks_base-a83ce1dd2ad3a6b71e90ff4845afc1299fe17b9d.tar.bz2 |
More work on collecting assist data.
Optimize parceling of AssistData (which is now renamed to
AssistStructure) by pooling duplicated class name strings.
Change text associated with a view node to a CharSequence,
so styling information comes along.
Include global text attributes -- size, colors, etc.
Introduce a new AssistContent structure, which allows us
to propagate information about the intent and data the
activity is looking at. This further allows us to propagate
permission grants, so the assistant can dig in to that data.
The default implementation propagates the base intent of an
activity, so if for example you bring up the assistant while
doing a share the assistant itself has the same information
and access that was given to the share activity (so it could
for example share it in another way if it wanted to).
Did some optimization of loading PersistableBundle from xml,
to avoid duplicating hash maps and such.
Changed how we dispatch ACTION_ASSIST to no longer include
the more detailed AssistStructure (and new AssistContent)
data when launching; now the example code that intercepts
that needs to be sure to ask for assist data when it starts
its session. This is more like it will finally be, and allows
us to get to the UI more quickly.
Change-Id: I88420a55761bf48d34ce3013e81bd96a0e087637
Diffstat (limited to 'services/voiceinteraction')
-rw-r--r-- | services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java | 123 |
1 files changed, 105 insertions, 18 deletions
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index e2b47c3..30d97b9 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -16,12 +16,17 @@ package com.android.server.voiceinteraction; +import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.AssistContent; import android.app.IActivityManager; +import android.content.ClipData; import android.content.ComponentName; +import android.content.ContentProvider; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -53,6 +58,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { final int mCallingUid; final IActivityManager mAm; final IWindowManager mIWindowManager; + final IBinder mPermissionOwner; boolean mShown; Bundle mShowArgs; int mShowFlags; @@ -83,15 +89,9 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { public void send(int resultCode, Bundle resultData) throws RemoteException { synchronized (mLock) { if (mShown) { - if (mSession != null) { - try { - mSession.handleAssist(resultData); - } catch (RemoteException e) { - } - } else { - mHaveAssistData = true; - mAssistData = resultData; - } + mHaveAssistData = true; + mAssistData = resultData; + deliverAssistData(); } } } @@ -109,6 +109,14 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mAm = ActivityManagerNative.getDefault(); mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); + IBinder permOwner = null; + try { + permOwner = mAm.newUriPermissionOwner("voicesession:" + + component.flattenToShortString()); + } catch (RemoteException e) { + Slog.w("voicesession", "AM dead", e); + } + mPermissionOwner = permOwner; mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); mBindIntent.setComponent(mSessionComponentName); mBound = mContext.bindServiceAsUser(mBindIntent, this, @@ -138,7 +146,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mShowFlags = flags; if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) { try { - mAm.requestAssistContextExtras(0, mAssistReceiver); + mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, + mAssistReceiver); } catch (RemoteException e) { } } else { @@ -152,20 +161,91 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mShowFlags = 0; } catch (RemoteException e) { } - if (mHaveAssistData) { - try { - mSession.handleAssist(mAssistData); - mAssistData = null; - mHaveAssistData = false; - } catch (RemoteException e) { - } - } + deliverAssistData(); } return true; } return false; } + void grantUriPermission(Uri uri, int mode, int srcUid, int destUid, String destPkg) { + if (!"content".equals(uri.getScheme())) { + return; + } + long ident = Binder.clearCallingIdentity(); + try { + // This will throw SecurityException for us. + mAm.checkGrantUriPermission(srcUid, null, ContentProvider.getUriWithoutUserId(uri), + mode, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(srcUid))); + // No security exception, do the grant. + int sourceUserId = ContentProvider.getUserIdFromUri(uri, mUser); + uri = ContentProvider.getUriWithoutUserId(uri); + mAm.grantUriPermissionFromOwner(mPermissionOwner, srcUid, destPkg, + uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, mUser); + } catch (RemoteException e) { + } catch (SecurityException e) { + Slog.w(TAG, "Can't propagate permission", e); + } finally { + Binder.restoreCallingIdentity(ident); + } + + } + + void grantClipDataItemPermission(ClipData.Item item, int mode, int srcUid, int destUid, + String destPkg) { + if (item.getUri() != null) { + grantUriPermission(item.getUri(), mode, srcUid, destUid, destPkg); + } + Intent intent = item.getIntent(); + if (intent != null && intent.getData() != null) { + grantUriPermission(intent.getData(), mode, srcUid, destUid, destPkg); + } + } + + void grantClipDataPermissions(ClipData data, int mode, int srcUid, int destUid, + String destPkg) { + final int N = data.getItemCount(); + for (int i=0; i<N; i++) { + grantClipDataItemPermission(data.getItemAt(i), mode, srcUid, destUid, destPkg); + } + } + + void deliverAssistData() { + if (mSession == null || !mHaveAssistData) { + return; + } + if (mAssistData != null) { + int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1); + if (uid >= 0) { + Bundle assistContext = mAssistData.getBundle(Intent.EXTRA_ASSIST_CONTEXT); + if (assistContext != null) { + AssistContent content = AssistContent.getAssistContent(assistContext); + if (content != null) { + Intent intent = content.getIntent(); + if (intent != null) { + ClipData data = intent.getClipData(); + if (data != null && Intent.isAccessUriMode(intent.getFlags())) { + grantClipDataPermissions(data, intent.getFlags(), uid, + mCallingUid, mSessionComponentName.getPackageName()); + } + } + ClipData data = content.getClipData(); + if (data != null) { + grantClipDataPermissions(data, Intent.FLAG_GRANT_READ_URI_PERMISSION, + uid, mCallingUid, mSessionComponentName.getPackageName()); + } + } + } + } + } + try { + mSession.handleAssist(mAssistData); + mAssistData = null; + mHaveAssistData = false; + } catch (RemoteException e) { + } + } + public boolean hideLocked() { if (mBound) { if (mShown) { @@ -180,6 +260,13 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { } catch (RemoteException e) { } } + try { + mAm.revokeUriPermissionFromOwner(mPermissionOwner, null, + Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION, + mUser); + } catch (RemoteException e) { + } } if (mFullyBound) { mContext.unbindService(mFullConnection); |