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

Commit dbafd00d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add unit tests for layout of window decoration" into tm-qpr-dev am: e4916371

parents 810f0e1d e4916371
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -222,10 +222,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>


        float shadowRadius = outResult.mDensity * shadowRadiusDp;
        float shadowRadius = outResult.mDensity * shadowRadiusDp;
        int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
        int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
        mTmpColor[0] = Color.red(backgroundColorInt);
        mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
        mTmpColor[1] = Color.green(backgroundColorInt);
        mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
        mTmpColor[2] = Color.blue(backgroundColorInt);
        mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
        t.setCrop(mTaskBackgroundSurface, taskBounds)
        t.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height())
                .setShadowRadius(mTaskBackgroundSurface, shadowRadius)
                .setShadowRadius(mTaskBackgroundSurface, shadowRadius)
                .setColor(mTaskBackgroundSurface, mTmpColor);
                .setColor(mTaskBackgroundSurface, mTmpColor);


+2 −3
Original line number Original line Diff line number Diff line
@@ -34,13 +34,12 @@ public class MockSurfaceControlHelper {
     * given {@link SurfaceControl} when calling {@link SurfaceControl.Builder#build()}.
     * given {@link SurfaceControl} when calling {@link SurfaceControl.Builder#build()}.
     *
     *
     * @param mockSurfaceControl the first {@link SurfaceControl} to return
     * @param mockSurfaceControl the first {@link SurfaceControl} to return
     * @param mockSurfaceControls following {@link SurfaceControl} to return
     * @return the mock of {@link SurfaceControl.Builder}
     * @return the mock of {@link SurfaceControl.Builder}
     */
     */
    public static SurfaceControl.Builder createMockSurfaceControlBuilder(
    public static SurfaceControl.Builder createMockSurfaceControlBuilder(
            SurfaceControl mockSurfaceControl, SurfaceControl... mockSurfaceControls) {
            SurfaceControl mockSurfaceControl) {
        final SurfaceControl.Builder mockBuilder = mock(SurfaceControl.Builder.class, RETURNS_SELF);
        final SurfaceControl.Builder mockBuilder = mock(SurfaceControl.Builder.class, RETURNS_SELF);
        doReturn(mockSurfaceControl, (Object[]) mockSurfaceControls)
        doReturn(mockSurfaceControl)
                .when(mockBuilder)
                .when(mockBuilder)
                .build();
                .build();
        return mockBuilder;
        return mockBuilder;
+151 −3
Original line number Original line Diff line number Diff line
@@ -21,23 +21,32 @@ import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceCon


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


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;


import android.app.ActivityManager;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.AndroidTestingRunner;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Display;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManager.LayoutParams;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
@@ -53,6 +62,8 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mock;


import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.function.Supplier;


/**
/**
@@ -66,6 +77,8 @@ import java.util.function.Supplier;
public class WindowDecorationTests extends ShellTestCase {
public class WindowDecorationTests extends ShellTestCase {
    private static final int CAPTION_HEIGHT_DP = 32;
    private static final int CAPTION_HEIGHT_DP = 32;
    private static final int SHADOW_RADIUS_DP = 5;
    private static final int SHADOW_RADIUS_DP = 5;
    private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
    private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);


    private final Rect mOutsetsDp = new Rect();
    private final Rect mOutsetsDp = new Rect();
    private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
    private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
@@ -84,18 +97,139 @@ public class WindowDecorationTests extends ShellTestCase {
    @Mock
    @Mock
    private WindowContainerTransaction mMockWindowContainerTransaction;
    private WindowContainerTransaction mMockWindowContainerTransaction;


    private SurfaceControl.Builder mMockSurfaceControlBuilder;
    private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
    private SurfaceControl.Transaction mMockSurfaceControlTransaction;
    private SurfaceControl.Transaction mMockSurfaceControlTransaction;


    @Before
    @Before
    public void setUp() {
    public void setUp() {
        mMockSurfaceControlBuilder = createMockSurfaceControlBuilder(mock(SurfaceControl.class));
        mMockSurfaceControlTransaction = createMockSurfaceControlTransaction();
        mMockSurfaceControlTransaction = createMockSurfaceControlTransaction();


        doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
        doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
                .create(any(), any(), any(), anyBoolean());
                .create(any(), any(), any(), anyBoolean());
    }
    }


    @Test
    public void testLayoutResultCalculation_invisibleTask() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
        final SurfaceControl.Builder decorContainerSurfaceBuilder =
                createMockSurfaceControlBuilder(decorContainerSurface);
        mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
        final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class);
        final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
                createMockSurfaceControlBuilder(taskBackgroundSurface);
        mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);

        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                new ActivityManager.TaskDescription.Builder()
                        .setBackgroundColor(Color.YELLOW);
        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setTaskDescriptionBuilder(taskDescriptionBuilder)
                .setBounds(TASK_BOUNDS)
                .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                .setVisible(false)
                .build();
        taskInfo.isFocused = false;
        // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is
        // 64px.
        taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
        mOutsetsDp.set(10, 20, 30, 40);

        final SurfaceControl taskSurface = mock(SurfaceControl.class);
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);

        windowDecor.relayout(taskInfo);

        verify(decorContainerSurfaceBuilder, never()).build();
        verify(taskBackgroundSurfaceBuilder, never()).build();
        verify(mMockSurfaceControlViewHostFactory, never())
                .create(any(), any(), any(), anyBoolean());

        verify(mMockSurfaceControlTransaction).hide(taskSurface);

        assertNull(mRelayoutResult.mRootView);
    }

    @Test
    public void testLayoutResultCalculation_visibleFocusedTask() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
        final SurfaceControl.Builder decorContainerSurfaceBuilder =
                createMockSurfaceControlBuilder(decorContainerSurface);
        mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
        final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class);
        final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
                createMockSurfaceControlBuilder(taskBackgroundSurface);
        mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);

        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                new ActivityManager.TaskDescription.Builder()
                        .setBackgroundColor(Color.YELLOW);
        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setTaskDescriptionBuilder(taskDescriptionBuilder)
                .setBounds(TASK_BOUNDS)
                .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                .setVisible(true)
                .build();
        taskInfo.isFocused = true;
        // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is
        // 64px.
        taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
        mOutsetsDp.set(10, 20, 30, 40);

        final SurfaceControl taskSurface = mock(SurfaceControl.class);
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);

        windowDecor.relayout(taskInfo);

        verify(decorContainerSurfaceBuilder).setParent(taskSurface);
        verify(decorContainerSurfaceBuilder).setContainerLayer();
        verify(mMockSurfaceControlTransaction).setTrustedOverlay(decorContainerSurface, true);
        verify(mMockSurfaceControlTransaction).setPosition(decorContainerSurface, -20, -40);
        verify(mMockSurfaceControlTransaction).setWindowCrop(decorContainerSurface, 380, 220);

        verify(taskBackgroundSurfaceBuilder).setParent(taskSurface);
        verify(taskBackgroundSurfaceBuilder).setEffectLayer();
        verify(mMockSurfaceControlTransaction).setWindowCrop(taskBackgroundSurface, 300, 100);
        verify(mMockSurfaceControlTransaction)
                .setColor(taskBackgroundSurface, new float[] {1.f, 1.f, 0.f});
        verify(mMockSurfaceControlTransaction).setShadowRadius(taskBackgroundSurface, 10);

        verify(mMockSurfaceControlViewHostFactory)
                .create(any(), eq(defaultDisplay), any(), anyBoolean());
        verify(mMockSurfaceControlViewHost)
                .setView(same(mMockView),
                        argThat(lp -> lp.height == 64
                                && lp.width == 300
                                && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0));
        if (ViewRootImpl.CAPTION_ON_SHELL) {
            verify(mMockView).setTaskFocusState(true);
            verify(mMockWindowContainerTransaction)
                    .addRectInsetsProvider(taskInfo.token,
                            new Rect(100, 300, 400, 364),
                            new int[] { InsetsState.ITYPE_CAPTION_BAR });
        }

        verify(mMockSurfaceControlTransaction)
                .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y);
        verify(mMockSurfaceControlTransaction)
                .setCrop(taskSurface, new Rect(-20, -40, 360, 180));
        verify(mMockSurfaceControlTransaction)
                .show(taskSurface);

        assertEquals(380, mRelayoutResult.mWidth);
        assertEquals(220, mRelayoutResult.mHeight);
        assertEquals(2, mRelayoutResult.mDensity, 0.f);
    }

    @Test
    @Test
    public void testNotCrashWhenDisplayAppearsAfterTask() {
    public void testNotCrashWhenDisplayAppearsAfterTask() {
        doReturn(mock(Display.class)).when(mMockDisplayController)
        doReturn(mock(Display.class)).when(mMockDisplayController)
@@ -145,10 +279,24 @@ public class WindowDecorationTests extends ShellTestCase {
    private TestWindowDecoration createWindowDecoration(
    private TestWindowDecoration createWindowDecoration(
            ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
            ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
        return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
        return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
                taskInfo, testSurface, () -> mMockSurfaceControlBuilder,
                taskInfo, testSurface, new MockSurfaceControlBuilderSupplier(),
                mMockSurfaceControlViewHostFactory);
                mMockSurfaceControlViewHostFactory);
    }
    }


    private class MockSurfaceControlBuilderSupplier implements Supplier<SurfaceControl.Builder> {
        private int mNumOfCalls = 0;

        @Override
        public SurfaceControl.Builder get() {
            final SurfaceControl.Builder builder =
                    mNumOfCalls < mMockSurfaceControlBuilders.size()
                            ? mMockSurfaceControlBuilders.get(mNumOfCalls)
                            : createMockSurfaceControlBuilder(mock(SurfaceControl.class));
            ++mNumOfCalls;
            return builder;
        }
    }

    private static class TestView extends View implements TaskFocusStateConsumer {
    private static class TestView extends View implements TaskFocusStateConsumer {
        private TestView(Context context) {
        private TestView(Context context) {
            super(context);
            super(context);