Merge "Enforce cross-uid touch pass-though opt-in" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 3ffab90..c33c053 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4919,6 +4919,7 @@
     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();
@@ -4932,6 +4933,7 @@
     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);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 91aa225..0d183c7 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -26,6 +26,7 @@
 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;
@@ -453,6 +454,10 @@
     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
@@ -554,6 +559,7 @@
     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
@@ -1416,6 +1422,7 @@
                 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));
     }
@@ -1839,6 +1846,39 @@
                 && 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;
@@ -2520,6 +2560,10 @@
         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;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 12d733f..f8e8ca4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2154,7 +2154,10 @@
         }
         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();
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index 1a19787..fa5beca 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -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.
@@ -35,6 +40,21 @@
     @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;
@@ -42,13 +62,24 @@
     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();
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index 5787780..4cd75d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -308,6 +308,8 @@
                     // 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;