diff --git a/api/current.txt b/api/current.txt index 68ecf968b73a0..e16294edb3805 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3341,6 +3341,7 @@ package android.app { method public boolean isImmersive(); method public boolean isTaskRoot(); method public boolean isVoiceInteraction(); + method public boolean isVoiceInteractionRoot(); method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public boolean moveTaskToBack(boolean); method public boolean navigateUpTo(android.content.Intent); diff --git a/api/system-current.txt b/api/system-current.txt index 2e0613a0d48b6..a784378e5f5f8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3444,6 +3444,7 @@ package android.app { method public boolean isImmersive(); method public boolean isTaskRoot(); method public boolean isVoiceInteraction(); + method public boolean isVoiceInteractionRoot(); method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String); method public boolean moveTaskToBack(boolean); method public boolean navigateUpTo(android.content.Intent); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index bdea6088c5296..3c8af0d5444ae 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1228,6 +1228,22 @@ public class Activity extends ContextThemeWrapper return mVoiceInteractor != null; } + /** + * Like {@link #isVoiceInteraction}, but only returns true if this is also the root + * of a voice interaction. That is, returns true if this activity was directly + * started by the voice interaction service as the initiation of a voice interaction. + * Otherwise, for example if it was started by another activity while under voice + * interaction, returns false. + */ + public boolean isVoiceInteractionRoot() { + try { + return mVoiceInteractor != null + && ActivityManagerNative.getDefault().isRootVoiceInteraction(mToken); + } catch (RemoteException e) { + } + return false; + } + /** * Retrieve the active {@link VoiceInteractor} that the user is going through to * interact with this activity. diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b758a7a5493d8..e144c297f50ea 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2582,6 +2582,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(res ? 1 : 0); return true; } + + case IS_ROOT_VOICE_INTERACTION_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + boolean res = isRootVoiceInteraction(token); + reply.writeNoException(); + reply.writeInt(res ? 1 : 0); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -5962,5 +5971,19 @@ class ActivityManagerProxy implements IActivityManager return res != 0; } + @Override + public boolean isRootVoiceInteraction(IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + mRemote.transact(IS_ROOT_VOICE_INTERACTION_TRANSACTION, data, reply, 0); + reply.readException(); + int res = reply.readInt(); + data.recycle(); + reply.recycle(); + return res != 0; + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 9ebbb9b9a671a..90216af3745cb 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -515,6 +515,8 @@ public interface IActivityManager extends IInterface { public boolean setProcessMemoryTrimLevel(String process, int uid, int level) throws RemoteException; + public boolean isRootVoiceInteraction(IBinder token) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -861,4 +863,5 @@ public interface IActivityManager extends IInterface { 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; + int IS_ROOT_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+301; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e8ffdb67d77ef..b8d32c3afb934 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6551,6 +6551,17 @@ public final class ActivityManagerService extends ActivityManagerNative } } + @Override + public boolean isRootVoiceInteraction(IBinder token) { + synchronized(this) { + ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null) { + return false; + } + return r.rootVoiceInteraction; + } + } + @Override public IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 0957eb5af1202..3de200954b15f 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -107,6 +107,7 @@ final class ActivityRecord { boolean fullscreen; // covers the full screen? final boolean noDisplay; // activity is not displayed? final boolean componentSpecified; // did caller specifiy an explicit component? + final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? static final int APPLICATION_ACTIVITY_TYPE = 0; static final int HOME_ACTIVITY_TYPE = 1; @@ -207,6 +208,9 @@ final class ActivityRecord { pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); pw.print(" componentSpecified="); pw.print(componentSpecified); pw.print(" mActivityType="); pw.println(mActivityType); + if (rootVoiceInteraction) { + pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction); + } pw.print(prefix); pw.print("compat="); pw.print(compat); pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); @@ -432,7 +436,8 @@ final class ActivityRecord { int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, - boolean _componentSpecified, ActivityStackSupervisor supervisor, + boolean _componentSpecified, boolean _rootVoiceInteraction, + ActivityStackSupervisor supervisor, ActivityContainer container, Bundle options) { service = _service; appToken = new Token(this, service); @@ -444,6 +449,7 @@ final class ActivityRecord { shortComponentName = _intent.getComponent().flattenToShortString(); resolvedType = _resolvedType; componentSpecified = _componentSpecified; + rootVoiceInteraction = _rootVoiceInteraction; configuration = _configuration; stackConfigOverride = (container != null) ? container.mStack.mOverrideConfig : Configuration.EMPTY; @@ -1257,7 +1263,7 @@ final class ActivityRecord { } final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid, launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(), - null, null, 0, componentSpecified, stackSupervisor, null, null); + null, null, 0, componentSpecified, false, stackSupervisor, null, null); r.persistentState = persistentState; r.taskDescription = taskDescription; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 0be2f6f4ec617..71fd49b71c987 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1506,6 +1506,7 @@ public final class ActivityStackSupervisor implements DisplayListener { if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) { try { + intent.addCategory(Intent.CATEGORY_VOICE); if (!AppGlobals.getPackageManager().activitySupportsIntent( intent.getComponent(), intent, resolvedType)) { err = ActivityManager.START_NOT_VOICE_COMPATIBLE; @@ -1626,7 +1627,7 @@ public final class ActivityStackSupervisor implements DisplayListener { ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, - requestCode, componentSpecified, this, container, options); + requestCode, componentSpecified, voiceSession != null, this, container, options); if (outActivity != null) { outActivity[0] = r; } @@ -3721,19 +3722,19 @@ public final class ActivityStackSupervisor implements DisplayListener { @Override public void onDisplayAdded(int displayId) { - Slog.v(TAG, "Display added displayId=" + displayId); + if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId); mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0)); } @Override public void onDisplayRemoved(int displayId) { - Slog.v(TAG, "Display removed displayId=" + displayId); + if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId); mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0)); } @Override public void onDisplayChanged(int displayId) { - Slog.v(TAG, "Display changed displayId=" + displayId); + if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId); mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0)); } diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml index d1a7ad532abde..277117e3e1570 100644 --- a/tests/VoiceInteraction/res/layout/test_interaction.xml +++ b/tests/VoiceInteraction/res/layout/test_interaction.xml @@ -34,6 +34,19 @@ android:textAppearance="?android:attr/textAppearanceMedium" /> + + +