No longer embedding activity if started-for-result across TFs

Instead of sending RESULT_CANCELED to the caller activity, let's
making sure the caller activity can get the result by stop embedding
the result activity in another TaskFragment.

Bug: 236668365
Test: atest TaskFragmentTest
Change-Id: I2a1d3203cc64df6a3b2004529d067990ae17d1d5
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 393c1be..96fe49e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -83,6 +83,7 @@
 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
+import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -3006,6 +3007,11 @@
                 errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
                 break;
             }
+            case EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT: {
+                errMsg = "Cannot embed activity across TaskFragments for result, resultTo: "
+                        + mStartActivity.resultTo;
+                break;
+            }
             default:
                 errMsg = "Unhandled embed result:" + result;
         }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index f8a9d46..128fe54 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -165,6 +165,13 @@
      * indicate that an Activity can't be embedded because the Activity is started on a new task.
      */
     static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
+    /**
+     * An embedding check result of
+     * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
+     * indicate that an Activity can't be embedded because the Activity is started on a new
+     * TaskFragment, e.g. start an Activity on a new TaskFragment for result.
+     */
+    static final int EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT = 4;
 
     /**
      * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
@@ -175,6 +182,7 @@
             EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
             EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
             EMBEDDING_DISALLOWED_NEW_TASK,
+            EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
     })
     @interface EmbeddingCheckResult {}
 
@@ -567,9 +575,17 @@
         if (!isAllowedToEmbedActivityInUntrustedMode(a)
                 && !isAllowedToEmbedActivityInTrustedMode(a, uid)) {
             return EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
-        } else if (smallerThanMinDimension(a)) {
+        }
+
+        if (smallerThanMinDimension(a)) {
             return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
         }
+
+        // Cannot embed activity across TaskFragments for activity result.
+        if (a.resultTo != null && a.resultTo.getTaskFragment() != this) {
+            return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
+        }
+
         return EMBEDDING_ALLOWED;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 5f30963..1096351 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -23,6 +23,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.os.Process.FIRST_APPLICATION_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -31,6 +32,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
+import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
+import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
+import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
@@ -433,6 +437,40 @@
     }
 
     @Test
+    public void testIsAllowedToEmbedActivity() {
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setCreateParentTask()
+                .createActivityCount(1)
+                .build();
+        final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+        // Not allow embedding activity if not a trusted host.
+        doReturn(false).when(taskFragment).isAllowedToEmbedActivityInUntrustedMode(any());
+        doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
+        assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
+                taskFragment.isAllowedToEmbedActivity(activity));
+
+        // Not allow embedding activity if the TaskFragment is smaller than activity min dimension.
+        doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
+        doReturn(true).when(taskFragment).smallerThanMinDimension(any());
+        assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
+                taskFragment.isAllowedToEmbedActivity(activity));
+
+        // Not allow to start activity across TaskFragments for result.
+        final TaskFragment newTaskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(taskFragment.getTask())
+                .build();
+        final ActivityRecord newActivity = new ActivityBuilder(mAtm)
+                .setUid(FIRST_APPLICATION_UID)
+                .build();
+        doReturn(true).when(newTaskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
+        doReturn(false).when(newTaskFragment).smallerThanMinDimension(any());
+        newActivity.resultTo = activity;
+        assertEquals(EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
+                newTaskFragment.isAllowedToEmbedActivity(newActivity));
+    }
+
+    @Test
     public void testIgnoreRequestedOrientationForActivityEmbeddingSplit() {
         // Setup two activities in ActivityEmbedding split.
         final Task task = createTask(mDisplayContent);