diff options
19 files changed, 262 insertions, 100 deletions
diff --git a/api/current.txt b/api/current.txt index ea33eaf..f15f699 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3466,6 +3466,7 @@ package android.app { method public final void setVolumeControlStream(int); method public boolean shouldShowRequestPermissionRationale(java.lang.String); method public boolean shouldUpRecreateTask(android.content.Intent); + method public boolean showAssist(android.os.Bundle); method public final deprecated void showDialog(int); method public final deprecated boolean showDialog(int, android.os.Bundle); method public void showLockTaskEscapeMessage(); @@ -28805,6 +28806,7 @@ package android.service.voice { method public android.content.Context getContext(); method public int getDisabledShowContext(); method public android.view.LayoutInflater getLayoutInflater(); + method public int getUserDisabledShowContext(); method public android.app.Dialog getWindow(); method public void hide(); method public void onAssistStructureFailure(java.lang.Throwable); @@ -28840,6 +28842,7 @@ package android.service.voice { method public void setTheme(int); method public void show(android.os.Bundle, int); method public void startVoiceActivity(android.content.Intent); + field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8 field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 field public static final int SHOW_WITH_ASSIST = 1; // 0x1 field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index d1e19fb..f9017dc 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3569,6 +3569,7 @@ package android.app { method public final void setVolumeControlStream(int); method public boolean shouldShowRequestPermissionRationale(java.lang.String); method public boolean shouldUpRecreateTask(android.content.Intent); + method public boolean showAssist(android.os.Bundle); method public final deprecated void showDialog(int); method public final deprecated boolean showDialog(int, android.os.Bundle); method public void showLockTaskEscapeMessage(); @@ -30957,6 +30958,7 @@ package android.service.voice { method public android.content.Context getContext(); method public int getDisabledShowContext(); method public android.view.LayoutInflater getLayoutInflater(); + method public int getUserDisabledShowContext(); method public android.app.Dialog getWindow(); method public void hide(); method public void onAssistStructureFailure(java.lang.Throwable); @@ -30992,6 +30994,7 @@ package android.service.voice { method public void setTheme(int); method public void show(android.os.Bundle, int); method public void startVoiceActivity(android.content.Intent); + field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8 field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 field public static final int SHOW_WITH_ASSIST = 1; // 0x1 field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 96c7f84..8d4ce62 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1545,6 +1545,24 @@ public class Activity extends ContextThemeWrapper } /** + * Ask to have the current assistant shown to the user. This only works if the calling + * activity is the current foreground activity. It is the same as calling + * {@link android.service.voice.VoiceInteractionService#showSession + * VoiceInteractionService.showSession} and requesting all of the possible context. + * The receiver will always see + * {@link android.service.voice.VoiceInteractionSession#SHOW_SOURCE_APPLICATION} set. + * @return Returns true if the assistant was successfully invoked, else false. For example + * false will be returned if the caller is not the current top activity. + */ + public boolean showAssist(Bundle args) { + try { + return ActivityManagerNative.getDefault().showAssistFromActivity(mToken, args); + } catch (RemoteException e) { + } + return false; + } + + /** * Called when you are no longer visible to the user. You will next * receive either {@link #onRestart}, {@link #onDestroy}, or nothing, * depending on later user activity. diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 9ca206a..55b2fd9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2807,7 +2807,7 @@ public class ActivityManager { /** * Request that the system start watching for the calling process to exceed a pss - * size as given here. Once called, the system will look for any occassions where it + * size as given here. Once called, the system will look for any occasions where it * sees the associated process with a larger pss size and, when this happens, automatically * pull a heap dump from it and allow the user to share the data. Note that this request * continues running even if the process is killed and restarted. To remove the watch, diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index bfb92c4..b758a7a 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2193,8 +2193,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); int requestType = data.readInt(); IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder()); - requestAssistContextExtras(requestType, receiver); + IBinder activityToken = data.readStrongBinder(); + boolean res = requestAssistContextExtras(requestType, receiver, activityToken); reply.writeNoException(); + reply.writeInt(res ? 1 : 0); return true; } @@ -2225,7 +2227,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - boolean res = isScreenCaptureAllowedOnCurrentActivity(); + boolean res = isAssistDataAllowedOnCurrentActivity(); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } + + case SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + Bundle args = data.readBundle(); + boolean res = showAssistFromActivity(token, args); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -5377,17 +5389,20 @@ class ActivityManagerProxy implements IActivityManager return res; } - public void requestAssistContextExtras(int requestType, IResultReceiver receiver) - throws RemoteException { + public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver, + IBinder activityToken) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(requestType); data.writeStrongBinder(receiver.asBinder()); + data.writeStrongBinder(activityToken); mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0); reply.readException(); + boolean res = reply.readInt() != 0; data.recycle(); reply.recycle(); + return res; } public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, @@ -5429,7 +5444,7 @@ class ActivityManagerProxy implements IActivityManager return res; } - public boolean isScreenCaptureAllowedOnCurrentActivity() throws RemoteException { + public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -5441,6 +5456,20 @@ class ActivityManagerProxy implements IActivityManager return res; } + public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + data.writeBundle(args); + mRemote.transact(SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION, data, reply, 0); + reply.readException(); + boolean res = reply.readInt() != 0; + data.recycle(); + reply.recycle(); + return res; + } + public void killUid(int uid, String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 5eb3961..9ebbb9b 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -434,8 +434,8 @@ public interface IActivityManager extends IInterface { public Bundle getAssistContextExtras(int requestType) throws RemoteException; - public void requestAssistContextExtras(int requestType, IResultReceiver receiver) - throws RemoteException; + public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver, + IBinder activityToken) throws RemoteException; public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException; @@ -443,7 +443,9 @@ public interface IActivityManager extends IInterface { public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle, Bundle args) throws RemoteException; - public boolean isScreenCaptureAllowedOnCurrentActivity() throws RemoteException; + public boolean isAssistDataAllowedOnCurrentActivity() throws RemoteException; + + public boolean showAssistFromActivity(IBinder token, Bundle args) throws RemoteException; public void killUid(int uid, String reason) throws RemoteException; @@ -858,4 +860,5 @@ public interface IActivityManager extends IInterface { int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298; int IS_SCREEN_CAPTURE_ALLOWED_ON_CURRENT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299; + int SHOW_ASSIST_FROM_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+300; } diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 95f96e8..a3ccbd3 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -91,6 +91,12 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall */ public static final int SHOW_SOURCE_ASSIST_GESTURE = 1<<2; + /** + * Flag for use with {@link #onShow}: indicates that the application itself has invoked + * the assistant. + */ + public static final int SHOW_SOURCE_APPLICATION = 1<<3; + final Context mContext; final HandlerCaller mHandlerCaller; @@ -936,6 +942,23 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } /** + * Return which show context flags have been disabled by the user through the system + * settings UI, so the session will never get this data. Returned flags are any combination of + * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and + * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT + * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}. Note that this only tells you about + * global user settings, not about restrictions that may be applied contextual based on + * the current application the user is in or other transient states. + */ + public int getUserDisabledShowContext() { + try { + return mSystemService.getUserDisabledShowContext(); + } catch (RemoteException e) { + return 0; + } + } + + /** * Show the UI for this session. This asks the system to go through the process of showing * your UI, which will eventually culminate in {@link #onShow}. This is similar to calling * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}. @@ -1179,23 +1202,33 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Called to receive data from the application that the user was currently viewing when - * an assist session is started. + * an assist session is started. If the original show request did not specify + * {@link #SHOW_WITH_ASSIST}, this method will not be called. * * @param data Arbitrary data supplied by the app through * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. + * May be null if assist data has been disabled by the user or device policy. * @param structure If available, the structure definition of all windows currently - * displayed by the app; if structure has been turned off by the user, will be null. + * displayed by the app. May be null if assist data has been disabled by the user + * or device policy; will be an empty stub if the application has disabled assist + * by marking its window as secure. * @param content Additional content data supplied by the app through * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. + * May be null if assist data has been disabled by the user or device policy; will + * not be automatically filled in with data from the app if the app has marked its + * window as secure. */ - public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) { + public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure, + @Nullable AssistContent content) { } /** * Called to receive a screenshot of what the user was currently viewing when an assist - * session is started. Will be null if screenshots are disabled by the user. + * session is started. May be null if screenshots are disabled by the user, policy, + * or application. If the original show request did not specify + * {@link #SHOW_WITH_SCREENSHOT}, this method will not be called. */ - public void onHandleScreenshot(Bitmap screenshot) { + public void onHandleScreenshot(@Nullable Bitmap screenshot) { } public boolean onKeyDown(int keyCode, KeyEvent event) { diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java index 6ba09c9..ff989bd 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; +import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; @@ -45,13 +46,15 @@ public class AssistUtils { ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); } - public void showSessionForActiveService(Bundle args, - IVoiceInteractionSessionShowCallback showCallback) { + public boolean showSessionForActiveService(Bundle args, int sourceFlags, + IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { try { - mVoiceInteractionManagerService.showSessionForActiveService(args, showCallback); + return mVoiceInteractionManagerService.showSessionForActiveService(args, sourceFlags, + showCallback, activityToken); } catch (RemoteException e) { Log.w(TAG, "Failed to call showSessionForActiveService", e); } + return false; } public void launchVoiceAssistFromKeyguard() { diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 73ad981..dc946ab 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -39,6 +39,7 @@ interface IVoiceInteractionManagerService { void finish(IBinder token); void setDisabledShowContext(int flags); int getDisabledShowContext(); + int getUserDisabledShowContext(); /** * Gets the registered Sound model for keyphrase detection for the current user. @@ -96,10 +97,12 @@ interface IVoiceInteractionManagerService { * affordances. * * @param args the bundle to pass as arguments to the voice interaction session - * @param showCallback callback to be notified when the session was shown + * @param sourceFlags flags indicating the source of this show + * @param showCallback optional callback to be notified when the session was shown + * @param activityToken optional token of activity that needs to be on top */ - void showSessionForActiveService(in Bundle args, - IVoiceInteractionSessionShowCallback showCallback); + boolean showSessionForActiveService(in Bundle args, int sourceFlags, + IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken); /** * Hides the session from the active service, if it is showing. diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 0daa5c9..f66a7dd 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -18,6 +18,7 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; +import android.service.voice.VoiceInteractionSession; import android.util.Log; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -218,7 +219,8 @@ public class AssistManager { } private void startVoiceInteractor(Bundle args) { - mAssistUtils.showSessionForActiveService(args, mShowCallback); + mAssistUtils.showSessionForActiveService(args, + VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, null); } public void launchVoiceAssistFromKeyguard() { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3bf6fde..eb6579c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -65,6 +65,7 @@ import android.os.storage.IMountService; import android.os.storage.MountServiceInternal; import android.os.storage.StorageManager; import android.service.voice.IVoiceInteractionSession; +import android.service.voice.VoiceInteractionSession; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; @@ -73,6 +74,7 @@ import android.view.Display; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.AssistUtils; import com.android.internal.app.DumpHeapActivity; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IVoiceInteractor; @@ -10686,7 +10688,7 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public Bundle getAssistContextExtras(int requestType) { PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null, - UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT); + null, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT); if (pae == null) { return null; } @@ -10707,7 +10709,7 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public boolean isScreenCaptureAllowedOnCurrentActivity() { + public boolean isAssistDataAllowedOnCurrentActivity() { int userId = mCurrentUserId; synchronized (this) { ActivityRecord activity = getFocusedStack().topActivity(); @@ -10722,13 +10724,41 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void requestAssistContextExtras(int requestType, IResultReceiver receiver) { - enqueueAssistContext(requestType, null, null, receiver, UserHandle.getCallingUserId(), - null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT); + public boolean showAssistFromActivity(IBinder token, Bundle args) { + long ident = Binder.clearCallingIdentity(); + try { + synchronized (this) { + ActivityRecord caller = ActivityRecord.forTokenLocked(token); + ActivityRecord top = getFocusedStack().topActivity(); + if (top != caller) { + Slog.w(TAG, "showAssistFromActivity failed: caller " + caller + + " is not current top " + top); + return false; + } + if (!top.nowVisible) { + Slog.w(TAG, "showAssistFromActivity failed: caller " + caller + + " is not visible"); + return false; + } + } + AssistUtils utils = new AssistUtils(mContext); + return utils.showSessionForActiveService(args, + VoiceInteractionSession.SHOW_SOURCE_APPLICATION, null, token); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver, + IBinder activityToken) { + return enqueueAssistContext(requestType, null, null, receiver, activityToken, + UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null; } private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint, - IResultReceiver receiver, int userHandle, Bundle args, long timeout) { + IResultReceiver receiver, IBinder activityToken, int userHandle, Bundle args, + long timeout) { enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO, "enqueueAssistContext()"); synchronized (this) { @@ -10741,9 +10771,13 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity); return null; } - if (activity.app.pid == Binder.getCallingPid()) { - Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity); - return null; + if (activityToken != null) { + ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken); + if (activity != caller) { + Slog.w(TAG, "enqueueAssistContext failed: caller " + caller + + " is not current top " + activity); + return null; + } } PendingAssistExtras pae; Bundle extras = new Bundle(); @@ -10854,7 +10888,7 @@ public final class ActivityManagerService extends ActivityManagerNative public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle, Bundle args) { - return enqueueAssistContext(requestType, intent, hint, null, userHandle, args, + return enqueueAssistContext(requestType, intent, hint, null, null, userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null; } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 42f879c..b57c413 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -448,7 +448,7 @@ public class VoiceInteractionManagerService extends SystemService { } final long caller = Binder.clearCallingIdentity(); try { - mImpl.showSessionLocked(args, flags, null /* showCallback */); + mImpl.showSessionLocked(args, flags, null, null); } finally { Binder.restoreCallingIdentity(caller); } @@ -463,12 +463,9 @@ public class VoiceInteractionManagerService extends SystemService { throw new SecurityException( "deliverNewSession without running voice interaction service"); } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, - interactor); + return mImpl.deliverNewSessionLocked(token, session, interactor); } finally { Binder.restoreCallingIdentity(caller); } @@ -484,7 +481,7 @@ public class VoiceInteractionManagerService extends SystemService { } final long caller = Binder.clearCallingIdentity(); try { - return mImpl.showSessionLocked(sessionArgs, flags, null /* showCallback */); + return mImpl.showSessionLocked(sessionArgs, flags, null, null); } finally { Binder.restoreCallingIdentity(caller); } @@ -533,11 +530,9 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "setKeepAwake without running voice interaction service"); return; } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.setKeepAwakeLocked(callingPid, callingUid, token, keepAwake); + mImpl.setKeepAwakeLocked(token, keepAwake); } finally { Binder.restoreCallingIdentity(caller); } @@ -551,11 +546,9 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "closeSystemDialogs without running voice interaction service"); return; } - final int callingPid = Binder.getCallingPid(); - final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.closeSystemDialogsLocked(callingPid, callingUid, token); + mImpl.closeSystemDialogsLocked(token); } finally { Binder.restoreCallingIdentity(caller); } @@ -585,16 +578,14 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "setDisabledShowContext without running voice interaction service"); return; } - final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - mImpl.setDisabledShowContextLocked(callingPid, callingUid, flags); + mImpl.setDisabledShowContextLocked(callingUid, flags); } finally { Binder.restoreCallingIdentity(caller); } } - } @Override @@ -604,16 +595,32 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "getDisabledShowContext without running voice interaction service"); return 0; } - final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - return mImpl.getDisabledShowContextLocked(callingPid, callingUid); + return mImpl.getDisabledShowContextLocked(callingUid); } finally { Binder.restoreCallingIdentity(caller); } } + } + @Override + public int getUserDisabledShowContext() { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, + "getUserDisabledShowContext without running voice interaction service"); + return 0; + } + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + return mImpl.getUserDisabledShowContextLocked(callingUid); + } finally { + Binder.restoreCallingIdentity(caller); + } + } } //----------------- Model management APIs --------------------------------// @@ -799,22 +806,22 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void showSessionForActiveService(Bundle args, - IVoiceInteractionSessionShowCallback showCallback) { + public boolean showSessionForActiveService(Bundle args, int sourceFlags, + IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); synchronized (this) { if (mImpl == null) { Slog.w(TAG, "showSessionForActiveService without running voice interaction" + "service"); - return; + return false; } final long caller = Binder.clearCallingIdentity(); try { - mImpl.showSessionLocked(args, - VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE + return mImpl.showSessionLocked(args, + sourceFlags | VoiceInteractionSession.SHOW_WITH_ASSIST | VoiceInteractionSession.SHOW_WITH_SCREENSHOT, - showCallback); + showCallback, activityToken); } finally { Binder.restoreCallingIdentity(caller); } @@ -908,7 +915,8 @@ public class VoiceInteractionManagerService extends SystemService { } private void enforceCallingPermission(String permission) { - if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) { + if (mContext.checkCallingOrSelfPermission(permission) + != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller does not hold the permission " + permission); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 7409f99..a4facc1 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -142,12 +142,13 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } public boolean showSessionLocked(Bundle args, int flags, - IVoiceInteractionSessionShowCallback showCallback) { + IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { if (mActiveSession == null) { mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName, mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler); } - return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback); + return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback, + activityToken); } public boolean hideSessionLocked() { @@ -157,7 +158,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return false; } - public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, + public boolean deliverNewSessionLocked(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor) { if (mActiveSession == null || token != mActiveSession.mToken) { Slog.w(TAG, "deliverNewSession does not match active session"); @@ -189,8 +190,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - public void setKeepAwakeLocked(int callingPid, int callingUid, IBinder token, - boolean keepAwake) { + public void setKeepAwakeLocked(IBinder token, boolean keepAwake) { try { if (mActiveSession == null || token != mActiveSession.mToken) { Slog.w(TAG, "setKeepAwake does not match active session"); @@ -202,7 +202,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - public void closeSystemDialogsLocked(int callingPid, int callingUid, IBinder token) { + public void closeSystemDialogsLocked(IBinder token) { try { if (mActiveSession == null || token != mActiveSession.mToken) { Slog.w(TAG, "closeSystemDialogs does not match active session"); @@ -223,7 +223,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession = null; } - public void setDisabledShowContextLocked(int callingPid, int callingUid, int flags) { + public void setDisabledShowContextLocked(int callingUid, int flags) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { throw new SecurityException("Calling uid " + callingUid @@ -232,7 +232,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mDisabledShowContext = flags; } - public int getDisabledShowContextLocked(int callingPid, int callingUid) { + public int getDisabledShowContextLocked(int callingUid) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { throw new SecurityException("Calling uid " + callingUid @@ -241,6 +241,15 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mDisabledShowContext; } + public int getUserDisabledShowContextLocked(int callingUid) { + int activeUid = mInfo.getServiceInfo().applicationInfo.uid; + if (callingUid != activeUid) { + throw new SecurityException("Calling uid " + callingUid + + " does not match active uid " + activeUid); + } + return mActiveSession != null ? mActiveSession.getUserDisabledShowContextLocked() : 0; + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index dfdd639..47a9fcd 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -183,8 +183,21 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { } } + public int getUserDisabledShowContextLocked() { + int flags = 0; + if (Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) == 0) { + flags |= VoiceInteractionSession.SHOW_WITH_ASSIST; + } + if (Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) == 0) { + flags |= VoiceInteractionSession.SHOW_WITH_SCREENSHOT; + } + return flags; + } + public boolean showLocked(Bundle args, int flags, int disabledContext, - IVoiceInteractionSessionShowCallback showCallback) { + IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { if (mBound) { if (!mFullyBound) { mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, @@ -193,18 +206,15 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { new UserHandle(mUser)); } mShown = true; - boolean isScreenCaptureAllowed = true; + boolean isAssistDataAllowed = true; try { - isScreenCaptureAllowed = mAm.isScreenCaptureAllowedOnCurrentActivity(); + isAssistDataAllowed = mAm.isAssistDataAllowedOnCurrentActivity(); } catch (RemoteException e) { } - boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0 - && isScreenCaptureAllowed + disabledContext |= getUserDisabledShowContextLocked(); + boolean structureEnabled = isAssistDataAllowed && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0; - boolean screenshotEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) != 0 - && isScreenCaptureAllowed + boolean screenshotEnabled = isAssistDataAllowed && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0; mShowArgs = args; mShowFlags = flags; @@ -215,9 +225,15 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED && structureEnabled) { try { - needDisclosure = true; - mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, - mAssistReceiver); + if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, + mAssistReceiver, activityToken)) { + needDisclosure = true; + } else { + // Wasn't allowed... given that, let's not do the screenshot either. + mHaveAssistData = true; + mAssistData = null; + screenshotEnabled = false; + } } catch (RemoteException e) { } } else { diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml index dc4e31b..b106437 100644 --- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml +++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml @@ -80,6 +80,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Disallow screenshot" /> + <TextView android:id="@+id/options_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:textAppearance="?android:attr/textAppearanceMedium" /> </LinearLayout> </LinearLayout> diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index 8381aa1..f1dd1de 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -74,21 +74,6 @@ public class MainInteractionService extends VoiceInteractionService { "Hello There", Locale.forLanguageTag("en-US"), mHotwordCallback); } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (isActiveService(this, new ComponentName(this, getClass()))) { - Bundle args = new Bundle(); - args.putParcelable("intent", new Intent(this, TestInteractionActivity.class)); - args.putBundle("assist", intent.getExtras()); - showSession(args, VoiceInteractionSession.SHOW_WITH_ASSIST - | VoiceInteractionSession.SHOW_WITH_SCREENSHOT); - } else { - Log.w(TAG, "Not starting -- not current voice interaction service"); - } - stopSelf(startId); - return START_NOT_STICKY; - } - private void hotwordAvailabilityChangeHelper(int availability) { Log.i(TAG, "Hotword availability = " + availability); switch (availability) { diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index 8796c9f..c0a67c1 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -50,6 +50,7 @@ public class MainInteractionSession extends VoiceInteractionSession View mOptionsContainer; CheckBox mDisallowAssist; CheckBox mDisallowScreenshot; + TextView mOptionsText; ImageView mScreenshot; ImageView mFullScreenshot; Button mConfirmButton; @@ -86,8 +87,9 @@ public class MainInteractionSession extends VoiceInteractionSession @Override public void onShow(Bundle args, int showFlags) { super.onShow(args, showFlags); + Log.i(TAG, "onShow: flags=0x" + Integer.toHexString(showFlags) + " args=" + args); mState = STATE_IDLE; - mStartIntent = args.getParcelable("intent"); + mStartIntent = args != null ? (Intent)args.getParcelable("intent") : null; if (mStartIntent == null) { mStartIntent = new Intent(getContext(), TestInteractionActivity.class); } @@ -96,6 +98,7 @@ public class MainInteractionSession extends VoiceInteractionSession } onHandleScreenshot(null); updateState(); + refreshOptions(); } @Override @@ -134,6 +137,7 @@ public class MainInteractionSession extends VoiceInteractionSession mDisallowAssist.setOnClickListener(this); mDisallowScreenshot = (CheckBox)mContentView.findViewById(R.id.disallow_screenshot); mDisallowScreenshot.setOnClickListener(this); + mOptionsText = (TextView)mContentView.findViewById(R.id.options_text); mConfirmButton = (Button)mContentView.findViewById(R.id.confirm); mConfirmButton.setOnClickListener(this); mCompleteButton = (Button)mContentView.findViewById(R.id.complete); @@ -145,13 +149,17 @@ public class MainInteractionSession extends VoiceInteractionSession } void refreshOptions() { - if (mOptionsCheck.isChecked()) { - mOptionsContainer.setVisibility(View.VISIBLE); - int flags = getDisabledShowContext(); - mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0); - mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0); - } else { - mOptionsContainer.setVisibility(View.GONE); + if (mOptionsContainer != null) { + if (mOptionsCheck.isChecked()) { + mOptionsContainer.setVisibility(View.VISIBLE); + int flags = getDisabledShowContext(); + mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0); + mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0); + int disabled = getUserDisabledShowContext(); + mOptionsText.setText("Disabled: 0x" + Integer.toHexString(disabled)); + } else { + mOptionsContainer.setVisibility(View.GONE); + } } } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java index b0d6b39..e10d89f 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -16,7 +16,6 @@ package com.android.test.voiceinteraction; -import android.annotation.Nullable; import android.app.Activity; import android.app.VoiceInteractor; import android.content.ComponentName; diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java index a7636c3..ee75f28 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java @@ -49,7 +49,7 @@ public class VoiceInteractionMain extends Activity { View.OnClickListener mStartListener = new View.OnClickListener() { public void onClick(View v) { - startService(new Intent(VoiceInteractionMain.this, MainInteractionService.class)); + showAssist(null); } }; } |