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

Commit bed3db4d authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Only show the toast of dismissing docked stack if it actually happens

When launching a non-resizable activity on secondary display, an overlay
activity will show "App may not work on a secondary display" on it.
Because the overlay activity is resizable, it is nothing to handle on
secondary display. But it falls to the condition of split-screen, and
even there is no docked stack, the toast of dismissing docked stack is
still shown.

Bug: 128674132
Test: atest ActivityStackSupervisorTests# \
      testHandleNonResizableTaskOnSecondaryDisplay

Change-Id: I1b8fe892ec4cace4f87112f132e0eefdae19024d
parent 9bb28c28
Loading
Loading
Loading
Loading
+18 −21
Original line number Diff line number Diff line
@@ -2453,46 +2453,43 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
                mService.getTaskChangeNotificationController()
                        .notifyActivityLaunchOnSecondaryDisplayFailed(task.getTaskInfo(),
                                preferredDisplayId);
                return;
            } else if (!forceNonResizable && handleForcedResizableTask(task,
                    FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY)) {
                return;
            } else if (!forceNonResizable) {
                handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY);
            }
            // The information about not support secondary display should already be notified, we
            // don't want to show another message on default display about split-screen. And it may
            // be the case that a resizable activity is launched on a non-resizable task.
            return;
        }

        if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
            // Display a warning toast that we tried to put an app that doesn't support split-screen
            // in split-screen.
            mService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack();

            // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
            // we need to move it to top of fullscreen stack, otherwise it will be covered.

            final ActivityStack dockedStack =
                    task.getStack().getDisplay().getSplitScreenPrimaryStack();
            if (dockedStack != null) {
                // Display a warning toast that we tried to put an app that doesn't support
                // split-screen in split-screen.
                mService.getTaskChangeNotificationController()
                        .notifyActivityDismissingDockedStack();
                moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
            }
            return;
        }

        handleForcedResizableTask(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
        handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
    }

    /**
     * @return {@code true} if the top activity of the task is forced to be resizable and the user
     *         was notified about activity being forced resized.
     */
    private boolean handleForcedResizableTask(TaskRecord task, int reason) {
    /** Notifies that the top activity of the task is forced to be resizeable. */
    private void handleForcedResizableTaskIfNeeded(TaskRecord task, int reason) {
        final ActivityRecord topActivity = task.getTopActivity();
        if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
                && !topActivity.noDisplay) {
            final String packageName = topActivity.appInfo.packageName;
            mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
                    task.taskId, reason, packageName);
            return true;
        if (topActivity == null || topActivity.noDisplay
                || !topActivity.isNonResizableOrForcedResizable()) {
            return;
        }
        return false;
        mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
                task.taskId, reason, topActivity.appInfo.packageName);
    }

    void activityRelaunchedLocked(IBinder token) {
+44 −10
Original line number Diff line number Diff line
@@ -18,32 +18,26 @@ package com.android.server.wm;

import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;

import android.app.WaitResult;
import android.content.pm.ActivityInfo;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.MediumTest;
@@ -112,4 +106,44 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
            assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent);
        }
    }

    /**
     * Ensures that {@link TaskChangeNotificationController} notifies only when an activity is
     * forced to resize on secondary display.
     */
    @Test
    public void testHandleNonResizableTaskOnSecondaryDisplay() {
        // Create an unresizable task on secondary display.
        final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
                .setDisplay(newDisplay).build();
        final ActivityRecord unresizableActivity = stack.getTopActivity();
        final TaskRecord task = unresizableActivity.getTaskRecord();
        unresizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
        task.setResizeMode(unresizableActivity.info.resizeMode);

        final TaskChangeNotificationController taskChangeNotifier =
                mService.getTaskChangeNotificationController();
        spyOn(taskChangeNotifier);

        mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
                newDisplay.mDisplayId, stack);
        // The top activity is unresizable, so it should notify the activity is forced resizing.
        verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.taskId),
                eq(FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY),
                eq(unresizableActivity.packageName));
        reset(taskChangeNotifier);

        // Put a resizable activity on top of the unresizable task.
        final ActivityRecord resizableActivity = new ActivityBuilder(mService)
                .setTask(task).build();
        resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;

        mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
                newDisplay.mDisplayId, stack);
        // For the resizable activity, it is no need to force resizing or dismiss the docked stack.
        verify(taskChangeNotifier, never()).notifyActivityForcedResizable(anyInt() /* taskId */,
                anyInt() /* reason */, anyString() /* packageName */);
        verify(taskChangeNotifier, never()).notifyActivityDismissingDockedStack();
    }
}