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

Commit 0342788c authored by Louis Chang's avatar Louis Chang
Browse files

Do not override finish activity behavior on back event

... if the activity was not started from Launcher.

The launcher activity was started from notification and was not
removed while swiping back. Another activity instance was added
on top of the same task when the app was started from Launcher
because the intent that started the task and the intent that
started from Launcher are different.

Also adding unit test to verify task is moved to back if the root
activity was started from Launcher.

Bug: 272723475
Test: atest ActivityRecordTests
Change-Id: I97ccce3a7491669ab6b649b6e1f053beae3828f0
parent 36fef761
Loading
Loading
Loading
Loading
+4 −34
Original line number Diff line number Diff line
@@ -78,8 +78,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
@@ -1645,18 +1643,15 @@ class ActivityClientController extends IActivityClientController.Stub {
                launchedFromHome = root.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME);
            }

            // If the activity is one of the main entry points for the application, then we should
            // If the activity was launched directly from the home screen, then we should
            // refrain from finishing the activity and instead move it to the back to keep it in
            // memory. The requirements for this are:
            //   1. The activity is the last running activity in the task.
            //   2. The current activity is the base activity for the task.
            //   3. a. If the activity was launched by the home process, we trust that its intent
            //         was resolved, so we check if the it is a main intent for the application.
            //      b. Otherwise, we query Package Manager to verify whether the activity is a
            //         launcher activity for the application.
            //   3. The activity was launched by the home process, and is one of the main entry
            //      points for the application.
            if (baseActivityIntent != null && isLastRunningActivity
                    && ((launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent))
                        || isLauncherActivity(baseActivityIntent.getComponent()))) {
                    && launchedFromHome && ActivityRecord.isMainIntent(baseActivityIntent)) {
                moveActivityTaskToBack(token, true /* nonRoot */);
                return;
            }
@@ -1668,31 +1663,6 @@ class ActivityClientController extends IActivityClientController.Stub {
        }
    }

    /**
     * Queries PackageManager to see if the given activity is one of the main entry point for the
     * application. This should not be called with the WM lock held.
     */
    @SuppressWarnings("unchecked")
    private boolean isLauncherActivity(@NonNull ComponentName activity) {
        final Intent queryIntent = new Intent(Intent.ACTION_MAIN);
        queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        queryIntent.setPackage(activity.getPackageName());
        try {
            final ParceledListSlice<ResolveInfo> resolved =
                    mService.getPackageManager().queryIntentActivities(
                            queryIntent, null, 0, mContext.getUserId());
            if (resolved == null) return false;
            for (final ResolveInfo ri : resolved.getList()) {
                if (ri.getComponentInfo().getComponentName().equals(activity)) {
                    return true;
                }
            }
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to query intent activities", e);
        }
        return false;
    }

    @Override
    public void enableTaskLocaleOverride(IBinder token) {
        if (UserHandle.getAppId(Binder.getCallingUid()) != SYSTEM_UID) {
+18 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
import static com.android.server.wm.ActivityRecord.LAUNCH_SOURCE_TYPE_HOME;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
import static com.android.server.wm.ActivityRecord.State.DESTROYING;
import static com.android.server.wm.ActivityRecord.State.FINISHING;
@@ -3682,6 +3683,23 @@ public class ActivityRecordTests extends WindowTestsBase {
        assertTrue(activity.inTransition());
    }

    /**
     * Verifies the task is moved to back when back pressed if the root activity was originally
     * started from Launcher.
     */
    @Test
    public void testMoveTaskToBackWhenStartedFromLauncher() {
        final Task task = createTask(mDisplayContent);
        final ActivityRecord ar = createActivityRecord(task);
        task.realActivity = ar.mActivityComponent;
        ar.intent.setAction(Intent.ACTION_MAIN);
        ar.intent.addCategory(Intent.CATEGORY_LAUNCHER);
        doReturn(true).when(ar).isLaunchSourceType(eq(LAUNCH_SOURCE_TYPE_HOME));

        mAtm.mActivityClientController.onBackPressed(ar.token, null /* callback */);
        verify(task).moveTaskToBack(any());
    }

    private ICompatCameraControlCallback getCompatCameraControlCallback() {
        return new ICompatCameraControlCallback.Stub() {
            @Override