Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d009305 authored by Louis Chang's avatar Louis Chang
Browse files

Allow starting activity for result on another TaskFragment

...but still in the same Task. This is only possible when
enabling ActivityEmbedding.

Meanwhile, the result should be sent immediately if the result-to
activity is in the RESUMED state.

Bug: 253387076
Test: atest TaskFragmentTest ActivityRecordTests
Change-Id: I9049e8cb2329836ac2661aa6ead679ffc838c3b8
parent dad85c36
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -3317,9 +3317,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
                        resultTo.getUriPermissionsLocked());
            }
            if (mForceSendResultForMediaProjection) {
                resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode,
                        resultData, resultGrants, true /* forceSendForMediaProjection */);
            if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) {
                // Sending the result to the resultTo activity asynchronously to prevent the
                // resultTo activity getting results before this Activity paused.
                final ActivityRecord resultToActivity = resultTo;
                mAtmService.mH.post(() -> {
                    synchronized (mAtmService.mGlobalLock) {
                        resultToActivity.sendResult(this.getUid(), resultWho, requestCode,
                                resultCode, resultData, resultGrants,
                                mForceSendResultForMediaProjection);
                    }
                });
            } else {
                resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
            }
@@ -4630,7 +4638,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                false /* forceSendForMediaProjection */);
    }

    private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
    void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
            Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) {
        if (callingUid > 0) {
            mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
+0 −6
Original line number Diff line number Diff line
@@ -78,7 +78,6 @@ import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
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;

@@ -2777,11 +2776,6 @@ class ActivityStarter {
                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;
        }
+0 −16
Original line number Diff line number Diff line
@@ -172,13 +172,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
     * 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
@@ -189,7 +182,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
            EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
            EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
            EMBEDDING_DISALLOWED_NEW_TASK,
            EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
    })
    @interface EmbeddingCheckResult {}

@@ -616,14 +608,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
            return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
        }

        // Cannot embed activity across TaskFragments for activity result.
        // If the activity that started for result is finishing, it's likely that this start mode
        // is used to place an activity in the same task. Since the finishing activity won't be
        // able to get the results, so it's OK to embed in a different TaskFragment.
        if (a.resultTo != null && !a.resultTo.finishing && a.resultTo.getTaskFragment() != this) {
            return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
        }

        return EMBEDDING_ALLOWED;
    }

+19 −0
Original line number Diff line number Diff line
@@ -1206,6 +1206,25 @@ public class ActivityRecordTests extends WindowTestsBase {
        }
    }

    @Test
    public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
        final Task task = new TaskBuilder(mSupervisor).build();
        final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
        final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
        final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
        final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
        resultToActivity.setState(RESUMED, "test");
        targetActivity.setState(RESUMED, "test");
        targetActivity.resultTo = resultToActivity;

        clearInvocations(mAtm.getLifecycleManager());
        targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
        waitUntilHandlersIdle();

        verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
                anyBoolean());
    }

    /**
     * Verify that complete finish request for non-finishing activity is invalid.
     */
+0 −20
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ 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.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
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;
@@ -33,9 +32,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
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_ALLOWED;
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;

@@ -475,23 +472,6 @@ public class TaskFragmentTest extends WindowTestsBase {
        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));

        // Allow embedding if the resultTo activity is finishing.
        activity.finishing = true;
        assertEquals(EMBEDDING_ALLOWED, newTaskFragment.isAllowedToEmbedActivity(newActivity));
    }

    @Test