Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -4919,6 +4919,7 @@ package android.app { method public int getPendingIntentBackgroundActivityStartMode(); method public int getPendingIntentCreatorBackgroundActivityStartMode(); method public int getSplashScreenStyle(); method @FlaggedApi("com.android.window.flags.touch_pass_through_opt_in") public boolean isAllowPassThroughOnTouchOutside(); method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed(); method public boolean isShareIdentityEnabled(); method public static android.app.ActivityOptions makeBasic(); Loading @@ -4932,6 +4933,7 @@ package android.app { method public static android.app.ActivityOptions makeTaskLaunchBehind(); method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method @FlaggedApi("com.android.window.flags.touch_pass_through_opt_in") public void setAllowPassThroughOnTouchOutside(boolean); method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); method public android.app.ActivityOptions setLaunchBounds(@Nullable android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int); core/java/android/app/ActivityOptions.java +44 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.view.Display.INVALID_DISPLAY; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -453,6 +454,10 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE = "android.activity.pendingIntentCreatorBackgroundActivityStartMode"; /** See {@link #setAllowPassThroughOnTouchOutside(boolean)}. */ private static final String KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE = "android.activity.allowPassThroughOnTouchOutside"; /** * @see #setLaunchCookie * @hide Loading Loading @@ -554,6 +559,7 @@ public class ActivityOptions extends ComponentOptions { private int mPendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; private boolean mDisableStartingWindow; private boolean mAllowPassThroughOnTouchOutside; /** * Create an ActivityOptions specifying a custom animation to run when Loading Loading @@ -1416,6 +1422,7 @@ public class ActivityOptions extends ComponentOptions { KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW); mAllowPassThroughOnTouchOutside = opts.getBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE); mAnimationAbortListener = IRemoteCallback.Stub.asInterface( opts.getBinder(KEY_ANIM_ABORT_LISTENER)); } Loading Loading @@ -1839,6 +1846,39 @@ public class ActivityOptions extends ComponentOptions { && mLaunchIntoPipParams.isLaunchIntoPip(); } /** * Returns whether the source activity allows the overlaying activities from the to-be-launched * app to pass through touch events to it when touches fall outside the content window. * * @see #setAllowPassThroughOnTouchOutside(boolean) */ @FlaggedApi(com.android.window.flags.Flags.FLAG_TOUCH_PASS_THROUGH_OPT_IN) public boolean isAllowPassThroughOnTouchOutside() { return mAllowPassThroughOnTouchOutside; } /** * Sets whether the source activity allows the overlaying activities from the to-be-launched * app to pass through touch events to it when touches fall outside the content window. * * <p> By default, touches that fall on a translucent non-touchable area of an overlaying * activity window are blocked from passing through to the activity below (source activity), * unless the overlaying activity is from the same UID as the source activity. The source * activity may use this method to opt in and allow the overlaying activities from the * to-be-launched app to pass through touches to itself. The source activity needs to ensure * that it trusts the overlaying activity and its content is not vulnerable to UI redressing * attacks. The flag is ignored if the context calling * {@link Context#startActivity(Intent, Bundle)} is not an activity. * * <p> For backward compatibility, apps with target SDK 35 and below may still receive * pass-through touches without opt-in if the cross-uid activity is launched by the source * activity. */ @FlaggedApi(com.android.window.flags.Flags.FLAG_TOUCH_PASS_THROUGH_OPT_IN) public void setAllowPassThroughOnTouchOutside(boolean allowed) { mAllowPassThroughOnTouchOutside = allowed; } /** @hide */ public int getLaunchActivityType() { return mLaunchActivityType; Loading Loading @@ -2520,6 +2560,10 @@ public class ActivityOptions extends ComponentOptions { if (mDisableStartingWindow) { b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow); } if (mAllowPassThroughOnTouchOutside) { b.putBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE, mAllowPassThroughOnTouchOutside); } b.putBinder(KEY_ANIM_ABORT_LISTENER, mAnimationAbortListener != null ? mAnimationAbortListener.asBinder() : null); return b; Loading services/core/java/com/android/server/wm/ActivityRecord.java +4 −1 Original line number Diff line number Diff line Loading @@ -2154,7 +2154,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName); mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord); final boolean appOptInTouchPassThrough = options != null && options.isAllowPassThroughOnTouchOutside(); mActivityRecordInputSink = new ActivityRecordInputSink( this, sourceRecord, appOptInTouchPassThrough); mAppActivityEmbeddingSplitsEnabled = isAppActivityEmbeddingSplitsEnabled(); mAllowUntrustedEmbeddingStateSharing = getAllowUntrustedEmbeddingStateSharingProperty(); Loading services/core/java/com/android/server/wm/ActivityRecordInputSink.java +33 −2 Original line number Diff line number Diff line Loading @@ -16,13 +16,18 @@ package com.android.server.wm; import android.app.ActivityOptions; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.os.Build; import android.os.InputConfig; import android.view.InputWindowHandle; import android.view.SurfaceControl; import android.view.WindowManager; import com.android.window.flags.Flags; /** * Creates a InputWindowHandle that catches all touches that would otherwise pass through an * Activity. Loading @@ -35,6 +40,21 @@ class ActivityRecordInputSink { @ChangeId static final long ENABLE_TOUCH_OPAQUE_ACTIVITIES = 194480991L; // TODO(b/369605358) Update EnabledSince when SDK 36 version code is available. /** * If the app's target SDK is 36+, pass-through touches from a cross-uid overlaying activity is * blocked by default. The activity may opt in to receive pass-through touches using * {@link ActivityOptions#setAllowPassThroughOnTouchOutside}, which allows the to-be-launched * cross-uid overlaying activity and other activities in that app to pass through touches. The * activity needs to ensure that it trusts the overlaying app and its content is not vulnerable * to UI redressing attacks. * * @see ActivityOptions#setAllowPassThroughOnTouchOutside */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT) static final long ENABLE_OVERLAY_TOUCH_PASS_THROUGH_OPT_IN_ENFORCEMENT = 358129114L; private final ActivityRecord mActivityRecord; private final boolean mIsCompatEnabled; private final String mName; Loading @@ -42,13 +62,24 @@ class ActivityRecordInputSink { private InputWindowHandleWrapper mInputWindowHandleWrapper; private SurfaceControl mSurfaceControl; ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) { ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord, boolean appOptInTouchPassThrough) { mActivityRecord = activityRecord; mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES, mActivityRecord.getUid()); mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink " + mActivityRecord.mActivityComponent.flattenToShortString(); if (sourceRecord != null) { if (sourceRecord == null) { return; } // If the source activity has target sdk 36+, it is required to opt in to receive // pass-through touches from the overlaying activity. final boolean isTouchPassThroughOptInEnforced = CompatChanges.isChangeEnabled( ENABLE_OVERLAY_TOUCH_PASS_THROUGH_OPT_IN_ENFORCEMENT, sourceRecord.getUid()); if (!Flags.touchPassThroughOptIn() || !isTouchPassThroughOptInEnforced || appOptInTouchPassThrough) { sourceRecord.mAllowedTouchUid = mActivityRecord.getUid(); } } Loading services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,8 @@ public class ActivityOptionsTest { // KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE case "android.activity.launchCookie": // KEY_LAUNCH_COOKIE case "android:activity.animAbortListener": // KEY_ANIM_ABORT_LISTENER case "android.activity.allowPassThroughOnTouchOutside": // KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE // Existing keys break; Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -4919,6 +4919,7 @@ package android.app { method public int getPendingIntentBackgroundActivityStartMode(); method public int getPendingIntentCreatorBackgroundActivityStartMode(); method public int getSplashScreenStyle(); method @FlaggedApi("com.android.window.flags.touch_pass_through_opt_in") public boolean isAllowPassThroughOnTouchOutside(); method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed(); method public boolean isShareIdentityEnabled(); method public static android.app.ActivityOptions makeBasic(); Loading @@ -4932,6 +4933,7 @@ package android.app { method public static android.app.ActivityOptions makeTaskLaunchBehind(); method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int); method public void requestUsageTimeReport(android.app.PendingIntent); method @FlaggedApi("com.android.window.flags.touch_pass_through_opt_in") public void setAllowPassThroughOnTouchOutside(boolean); method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle); method public android.app.ActivityOptions setLaunchBounds(@Nullable android.graphics.Rect); method public android.app.ActivityOptions setLaunchDisplayId(int);
core/java/android/app/ActivityOptions.java +44 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.view.Display.INVALID_DISPLAY; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -453,6 +454,10 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE = "android.activity.pendingIntentCreatorBackgroundActivityStartMode"; /** See {@link #setAllowPassThroughOnTouchOutside(boolean)}. */ private static final String KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE = "android.activity.allowPassThroughOnTouchOutside"; /** * @see #setLaunchCookie * @hide Loading Loading @@ -554,6 +559,7 @@ public class ActivityOptions extends ComponentOptions { private int mPendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; private boolean mDisableStartingWindow; private boolean mAllowPassThroughOnTouchOutside; /** * Create an ActivityOptions specifying a custom animation to run when Loading Loading @@ -1416,6 +1422,7 @@ public class ActivityOptions extends ComponentOptions { KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW); mAllowPassThroughOnTouchOutside = opts.getBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE); mAnimationAbortListener = IRemoteCallback.Stub.asInterface( opts.getBinder(KEY_ANIM_ABORT_LISTENER)); } Loading Loading @@ -1839,6 +1846,39 @@ public class ActivityOptions extends ComponentOptions { && mLaunchIntoPipParams.isLaunchIntoPip(); } /** * Returns whether the source activity allows the overlaying activities from the to-be-launched * app to pass through touch events to it when touches fall outside the content window. * * @see #setAllowPassThroughOnTouchOutside(boolean) */ @FlaggedApi(com.android.window.flags.Flags.FLAG_TOUCH_PASS_THROUGH_OPT_IN) public boolean isAllowPassThroughOnTouchOutside() { return mAllowPassThroughOnTouchOutside; } /** * Sets whether the source activity allows the overlaying activities from the to-be-launched * app to pass through touch events to it when touches fall outside the content window. * * <p> By default, touches that fall on a translucent non-touchable area of an overlaying * activity window are blocked from passing through to the activity below (source activity), * unless the overlaying activity is from the same UID as the source activity. The source * activity may use this method to opt in and allow the overlaying activities from the * to-be-launched app to pass through touches to itself. The source activity needs to ensure * that it trusts the overlaying activity and its content is not vulnerable to UI redressing * attacks. The flag is ignored if the context calling * {@link Context#startActivity(Intent, Bundle)} is not an activity. * * <p> For backward compatibility, apps with target SDK 35 and below may still receive * pass-through touches without opt-in if the cross-uid activity is launched by the source * activity. */ @FlaggedApi(com.android.window.flags.Flags.FLAG_TOUCH_PASS_THROUGH_OPT_IN) public void setAllowPassThroughOnTouchOutside(boolean allowed) { mAllowPassThroughOnTouchOutside = allowed; } /** @hide */ public int getLaunchActivityType() { return mLaunchActivityType; Loading Loading @@ -2520,6 +2560,10 @@ public class ActivityOptions extends ComponentOptions { if (mDisableStartingWindow) { b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow); } if (mAllowPassThroughOnTouchOutside) { b.putBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE, mAllowPassThroughOnTouchOutside); } b.putBinder(KEY_ANIM_ABORT_LISTENER, mAnimationAbortListener != null ? mAnimationAbortListener.asBinder() : null); return b; Loading
services/core/java/com/android/server/wm/ActivityRecord.java +4 −1 Original line number Diff line number Diff line Loading @@ -2154,7 +2154,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mAtmService.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, packageName); mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord); final boolean appOptInTouchPassThrough = options != null && options.isAllowPassThroughOnTouchOutside(); mActivityRecordInputSink = new ActivityRecordInputSink( this, sourceRecord, appOptInTouchPassThrough); mAppActivityEmbeddingSplitsEnabled = isAppActivityEmbeddingSplitsEnabled(); mAllowUntrustedEmbeddingStateSharing = getAllowUntrustedEmbeddingStateSharingProperty(); Loading
services/core/java/com/android/server/wm/ActivityRecordInputSink.java +33 −2 Original line number Diff line number Diff line Loading @@ -16,13 +16,18 @@ package com.android.server.wm; import android.app.ActivityOptions; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.os.Build; import android.os.InputConfig; import android.view.InputWindowHandle; import android.view.SurfaceControl; import android.view.WindowManager; import com.android.window.flags.Flags; /** * Creates a InputWindowHandle that catches all touches that would otherwise pass through an * Activity. Loading @@ -35,6 +40,21 @@ class ActivityRecordInputSink { @ChangeId static final long ENABLE_TOUCH_OPAQUE_ACTIVITIES = 194480991L; // TODO(b/369605358) Update EnabledSince when SDK 36 version code is available. /** * If the app's target SDK is 36+, pass-through touches from a cross-uid overlaying activity is * blocked by default. The activity may opt in to receive pass-through touches using * {@link ActivityOptions#setAllowPassThroughOnTouchOutside}, which allows the to-be-launched * cross-uid overlaying activity and other activities in that app to pass through touches. The * activity needs to ensure that it trusts the overlaying app and its content is not vulnerable * to UI redressing attacks. * * @see ActivityOptions#setAllowPassThroughOnTouchOutside */ @ChangeId @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT) static final long ENABLE_OVERLAY_TOUCH_PASS_THROUGH_OPT_IN_ENFORCEMENT = 358129114L; private final ActivityRecord mActivityRecord; private final boolean mIsCompatEnabled; private final String mName; Loading @@ -42,13 +62,24 @@ class ActivityRecordInputSink { private InputWindowHandleWrapper mInputWindowHandleWrapper; private SurfaceControl mSurfaceControl; ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) { ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord, boolean appOptInTouchPassThrough) { mActivityRecord = activityRecord; mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES, mActivityRecord.getUid()); mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink " + mActivityRecord.mActivityComponent.flattenToShortString(); if (sourceRecord != null) { if (sourceRecord == null) { return; } // If the source activity has target sdk 36+, it is required to opt in to receive // pass-through touches from the overlaying activity. final boolean isTouchPassThroughOptInEnforced = CompatChanges.isChangeEnabled( ENABLE_OVERLAY_TOUCH_PASS_THROUGH_OPT_IN_ENFORCEMENT, sourceRecord.getUid()); if (!Flags.touchPassThroughOptIn() || !isTouchPassThroughOptInEnforced || appOptInTouchPassThrough) { sourceRecord.mAllowedTouchUid = mActivityRecord.getUid(); } } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -308,6 +308,8 @@ public class ActivityOptionsTest { // KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE case "android.activity.launchCookie": // KEY_LAUNCH_COOKIE case "android:activity.animAbortListener": // KEY_ANIM_ABORT_LISTENER case "android.activity.allowPassThroughOnTouchOutside": // KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE // Existing keys break; Loading