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

Commit 671b40e5 authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Separate and add more SizeCompat tests; add Display Builder"

parents 96feb9bb 0177507b
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -6171,8 +6171,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // The rest of the condition is that only one side is smaller than the parent, but it still
        // needs to exclude the cases where the size is limited by the fixed aspect ratio.
        if (info.maxAspectRatio > 0) {
            final float aspectRatio = (0.5f + Math.max(appWidth, appHeight))
                    / Math.min(appWidth, appHeight);
            final float aspectRatio = Math.max(appWidth, appHeight) / Math.min(appWidth, appHeight);
            if (aspectRatio >= info.maxAspectRatio) {
                // The current size has reached the max aspect ratio.
                return false;
+0 −55
Original line number Diff line number Diff line
@@ -38,12 +38,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;

import android.app.TaskStackListener;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;
@@ -51,10 +46,6 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * Tests for the {@link ActivityDisplay} class.
 *
@@ -331,50 +322,4 @@ public class ActivityDisplayTests extends ActivityTestsBase {
        verify(mSupervisor).removeTaskByIdLocked(eq(task1.mTaskId), anyBoolean(), anyBoolean(),
                any());
    }

    /**
     * Ensures that {@link TaskStackListener} can receive callback about the activity in size
     * compatibility mode.
     */
    @Test
    public void testHandleActivitySizeCompatMode() throws Exception {
        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
        final ActivityRecord activity = createFullscreenStackWithSimpleActivityAt(
                display).topRunningActivityLocked();
        activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
        when(activity.getRequestedOrientation()).thenReturn(
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        activity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
        activity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        activity.visible = true;
        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);

        final ArrayList<CompletableFuture<IBinder>> resultWrapper = new ArrayList<>();
        mService.getTaskChangeNotificationController().registerTaskStackListener(
                new TaskStackListener() {
                    @Override
                    public void onSizeCompatModeActivityChanged(int displayId,
                            IBinder activityToken) {
                        resultWrapper.get(0).complete(activityToken);
                    }
                });

        resultWrapper.add(new CompletableFuture<>());

        // resize the display to exercise size-compat mode
        final DisplayContent displayContent = display.mDisplayContent;
        displayContent.mBaseDisplayHeight = (int) (0.8f * displayContent.mBaseDisplayHeight);
        Configuration c = new Configuration();
        displayContent.computeScreenConfiguration(c);
        display.onRequestedOverrideConfigurationChanged(c);

        assertEquals(activity.appToken, resultWrapper.get(0).get(2, TimeUnit.SECONDS));

        // Expect null token when switching to non-size-compat mode activity.
        activity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
        resultWrapper.set(0, new CompletableFuture<>());
        display.handleActivitySizeCompatModeIfNeeded(activity);

        assertNull(resultWrapper.get(0).get(2, TimeUnit.SECONDS));
    }
}
+0 −267
Original line number Diff line number Diff line
@@ -18,24 +18,18 @@ package com.android.server.wm;

import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -61,18 +55,13 @@ 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.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.PauseActivityItem;
@@ -80,13 +69,11 @@ import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.RemoteAnimationAdapter;
@@ -218,23 +205,6 @@ public class ActivityRecordTests extends ActivityTestsBase {
        assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
    }

    @Test
    public void testRestartProcessIfVisible() {
        doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
        mActivity.visible = true;
        mActivity.setSavedState(null /* savedState */);
        mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
        prepareFixedAspectRatioUnresizableActivity();

        final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
        setupDisplayAndParentSize(600, 1200);
        // The visible activity should recompute configuration according to the last parent bounds.
        mService.restartActivityProcessIfVisible(mActivity.appToken);

        assertEquals(ActivityStack.ActivityState.RESTARTING_PROCESS, mActivity.getState());
        assertNotEquals(originalOverrideBounds, mActivity.getBounds());
    }

    @Test
    public void testsApplyOptionsLocked() {
        ActivityOptions activityOptions = ActivityOptions.makeBasic();
@@ -483,214 +453,6 @@ public class ActivityRecordTests extends ActivityTestsBase {
        assertEquals(STARTED, mActivity.getState());
    }

    @Test
    public void testSizeCompatMode_KeepBoundsWhenChangingFromFreeformToFullscreen() {
        setupDisplayContentForCompatDisplayInsets();

        // put display in freeform mode
        ActivityDisplay display = mActivity.getDisplay();
        final Configuration c = new Configuration(display.getRequestedOverrideConfiguration());
        c.windowConfiguration.setBounds(new Rect(0, 0, 2000, 1000));
        c.densityDpi = 300;
        c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
        display.onRequestedOverrideConfigurationChanged(c);

        // launch compat activity in freeform and store bounds
        when(mActivity.getRequestedOrientation()).thenReturn(
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
        mTask.setBounds(100, 100, 400, 600);
        mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
        mActivity.visible = true;
        ensureActivityConfiguration();

        final Rect bounds = new Rect(mActivity.getBounds());
        final int density = mActivity.getConfiguration().densityDpi;

        // change display configuration to fullscreen
        c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
        display.onRequestedOverrideConfigurationChanged(c);

        // check if dimensions stay the same
        assertTrue(mActivity.inSizeCompatMode());
        assertEquals(bounds.width(), mActivity.getBounds().width());
        assertEquals(bounds.height(), mActivity.getBounds().height());
        assertEquals(density, mActivity.getConfiguration().densityDpi);
        assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN, mActivity.getWindowingMode());
    }

    @Test
    public void testSizeCompatMode_FixedAspectRatioBoundsWithDecor() {
        setupDisplayContentForCompatDisplayInsets();
        final int decorHeight = 200; // e.g. The device has cutout.
        final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy();
        spyOn(policy);
        doAnswer(invocationOnMock -> {
            final int rotation = invocationOnMock.<Integer>getArgument(0);
            final Rect insets = invocationOnMock.<Rect>getArgument(4);
            if (rotation == ROTATION_0) {
                insets.top = decorHeight;
            } else if (rotation == ROTATION_90) {
                insets.left = decorHeight;
            }
            return null;
        }).when(policy).getNonDecorInsetsLw(anyInt() /* rotation */, anyInt() /* width */,
                anyInt() /* height */, any() /* displayCutout */, any() /* outInsets */);
        // set appBounds to incorporate decor
        final Configuration c =
                new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
        c.windowConfiguration.getAppBounds().top = decorHeight;
        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);

        doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                .when(mActivity).getRequestedOrientation();
        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
        mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
        mActivity.visible = true;
        ensureActivityConfiguration();
        // The parent configuration doesn't change since the first resolved configuration, so the
        // activity shouldn't be in the size compatibility mode.
        assertFalse(mActivity.inSizeCompatMode());

        final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
        // Ensure the app bounds keep the declared aspect ratio.
        assertEquals(appBounds.width(), appBounds.height());
        // The decor height should be a part of the effective bounds.
        assertEquals(mActivity.getBounds().height(), appBounds.height() + decorHeight);

        mTask.getConfiguration().windowConfiguration.setRotation(ROTATION_90);
        mActivity.onConfigurationChanged(mTask.getConfiguration());
        // After changing orientation, the aspect ratio should be the same.
        assertEquals(appBounds.width(), appBounds.height());
        // The decor height will be included in width.
        assertEquals(mActivity.getBounds().width(), appBounds.width() + decorHeight);
    }

    @Test
    public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
        // Initialize different bounds on a new display.
        final Rect newDisplayBounds = new Rect(0, 0, 1000, 2000);
        DisplayInfo info = new DisplayInfo();
        mService.mContext.getDisplay().getDisplayInfo(info);
        info.logicalWidth = newDisplayBounds.width();
        info.logicalHeight = newDisplayBounds.height();
        info.logicalDensityDpi = 300;

        final ActivityDisplay newDisplay =
                addNewActivityDisplayAt(info, ActivityDisplay.POSITION_TOP);

        final Configuration c =
                new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
        c.densityDpi = 200;
        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
        mActivity = new ActivityBuilder(mService)
                .setTask(mTask)
                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                .setMaxAspectRatio(1.5f)
                .build();
        mActivity.visible = true;

        final Rect originalBounds = new Rect(mActivity.getBounds());
        final int originalDpi = mActivity.getConfiguration().densityDpi;

        // Move the non-resizable activity to the new display.
        mStack.reparent(newDisplay.mDisplayContent, true /* onTop */);

        assertEquals(originalBounds.width(),
                mActivity.getWindowConfiguration().getBounds().width());
        assertEquals(originalBounds.height(),
                mActivity.getWindowConfiguration().getBounds().height());
        assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
        assertTrue(mActivity.inSizeCompatMode());
    }

    @Test
    public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
        setupDisplayContentForCompatDisplayInsets();
        when(mActivity.getRequestedOrientation()).thenReturn(
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
        mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
        mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
        mActivity.visible = true;

        ensureActivityConfiguration();
        final Rect originalBounds = new Rect(mActivity.getBounds());

        // Change the size of current display.
        setupDisplayAndParentSize(1000, 2000);
        ensureActivityConfiguration();

        assertEquals(originalBounds.width(),
                mActivity.getWindowConfiguration().getBounds().width());
        assertEquals(originalBounds.height(),
                mActivity.getWindowConfiguration().getBounds().height());
        assertTrue(mActivity.inSizeCompatMode());
    }

    @Test
    public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
        final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
                | Configuration.SCREENLAYOUT_SIZE_NORMAL;
        final int layoutMask = Configuration.SCREENLAYOUT_LONG_MASK
                | Configuration.SCREENLAYOUT_SIZE_MASK
                | Configuration.SCREENLAYOUT_LAYOUTDIR_MASK;
        mTask.getRequestedOverrideConfiguration().screenLayout = fixedScreenLayout
                | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
        prepareFixedAspectRatioUnresizableActivity();

        // The initial configuration should inherit from parent.
        assertEquals(mTask.getConfiguration().screenLayout & layoutMask,
                mActivity.getConfiguration().screenLayout & layoutMask);

        mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
                | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
        mActivity.onConfigurationChanged(mTask.getConfiguration());

        // The size and aspect ratio bits don't change, but the layout direction should be updated.
        assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
                mActivity.getConfiguration().screenLayout & layoutMask);
    }

    @Test
    public void testSizeCompatMode_ResetNonVisibleActivity() {
        final ActivityDisplay display = mStack.getDisplay();
        spyOn(display);

        prepareFixedAspectRatioUnresizableActivity();
        mActivity.setState(STOPPED, "testSizeCompatMode");
        mActivity.visible = false;
        mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
        // Make the parent bounds to be different so the activity is in size compatibility mode.
        setupDisplayAndParentSize(600, 1200);

        // Simulate the display changes orientation.
        doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION
                | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
                        .when(display).getLastOverrideConfigurationChanges();
        mActivity.onConfigurationChanged(mTask.getConfiguration());
        when(display.getLastOverrideConfigurationChanges()).thenCallRealMethod();
        // The override configuration should not change so it is still in size compatibility mode.
        assertTrue(mActivity.inSizeCompatMode());

        // Change display density
        final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
        displayContent.mBaseDisplayDensity = (int) (0.7f * displayContent.mBaseDisplayDensity);
        final Configuration c = new Configuration();
        displayContent.computeScreenConfiguration(c);
        mService.mAmInternal = mock(ActivityManagerInternal.class);
        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);

        // The override configuration should be reset and the activity's process will be killed.
        assertFalse(mActivity.inSizeCompatMode());
        verify(mActivity).restartProcessIfVisible();
        waitHandlerIdle(mService.mH);
        verify(mService.mAmInternal).killProcess(
                eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
    }

    @Test
    public void testTakeOptions() {
        ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
@@ -1340,33 +1102,4 @@ public class ActivityRecordTests extends ActivityTestsBase {

        verify(mActivity).removeFromHistory(anyString());
    }

    /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
    private void prepareFixedAspectRatioUnresizableActivity() {
        setupDisplayContentForCompatDisplayInsets();
        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
        mActivity.info.maxAspectRatio = 1.5f;
        mActivity.visible = true;
        ensureActivityConfiguration();
    }

    private void setupDisplayContentForCompatDisplayInsets() {
        final Rect displayBounds = mStack.getDisplay().getBounds();
        setupDisplayAndParentSize(displayBounds.width(), displayBounds.height());
    }

    private DisplayContent setupDisplayAndParentSize(int width, int height) {
        final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
        displayContent.mBaseDisplayWidth = width;
        displayContent.mBaseDisplayHeight = height;
        final Configuration c =
                new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
        c.windowConfiguration.setBounds(new Rect(0, 0, width, height));
        c.windowConfiguration.setAppBounds(0, 0, width, height);
        c.windowConfiguration.setRotation(ROTATION_0);
        c.orientation = width > height
                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
        return displayContent;
    }
}
+1 −5
Original line number Diff line number Diff line
@@ -715,14 +715,10 @@ public class DisplayContentTests extends WindowTestsBase {

        activity.setRequestedOrientation(newOrientation);

        final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
        verify(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
                same(activity), anyBoolean(), same(null));
        final Configuration newDisplayConfig = captor.getValue();
        final int expectedOrientation = newOrientation == SCREEN_ORIENTATION_PORTRAIT
                ? Configuration.ORIENTATION_PORTRAIT
                : Configuration.ORIENTATION_LANDSCAPE;
        assertEquals(expectedOrientation, newDisplayConfig.orientation);
        assertEquals(expectedOrientation, dc.getConfiguration().orientation);
    }

    @Test
+426 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading