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

Commit db62abfc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "pip-tests-migration"

* changes:
  Removes default/movement PiP bounds from WM
  Adds unit tests for PipBoundsHandler
parents 1153c6ea 35d59141
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -53,9 +53,4 @@ interface IPinnedStackController {
     * {@param bounds} here is the final destination bounds.
     */
    void resetBoundsAnimation(in Rect bounds);

    /**
     * Reports the current default and movement bounds to controller.
     */
    void reportBounds(in Rect defaultBounds, in Rect movementBounds);
}
+4 −3
Original line number Diff line number Diff line
@@ -147,7 +147,8 @@ message DisplayContentProto {
    optional int32 id = 2;
    repeated StackProto stacks = 3;
    optional DockedStackDividerControllerProto docked_stack_divider_controller = 4;
    optional PinnedStackControllerProto pinned_stack_controller = 5;
    // Will be removed soon.
    optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
    /* non app windows */
    repeated WindowTokenProto above_app_windows = 6;
    repeated WindowTokenProto below_app_windows = 7;
@@ -184,8 +185,8 @@ message DockedStackDividerControllerProto {
message PinnedStackControllerProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional .android.graphics.RectProto default_bounds = 1;
    optional .android.graphics.RectProto movement_bounds = 2;
    optional .android.graphics.RectProto default_bounds = 1 [deprecated=true];
    optional .android.graphics.RectProto movement_bounds = 2 [deprecated=true];
}

/* represents TaskStack */
+0 −3
Original line number Diff line number Diff line
@@ -261,8 +261,6 @@ public class PipBoundsHandler {
            mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
                    -1 /* animationDuration */);
            mLastDestinationBounds.set(destinationBounds);
            mPinnedStackController.reportBounds(defaultBounds,
                    getMovementBounds(defaultBounds));
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to start PiP animation from SysUI", e);
        }
@@ -317,7 +315,6 @@ public class PipBoundsHandler {
            outBounds.set(postChangeStackBounds);
            mLastDestinationBounds.set(outBounds);
            mPinnedStackController.resetBoundsAnimation(outBounds);
            mPinnedStackController.reportBounds(outBounds, getMovementBounds(outBounds));
            t.setBounds(pinnedStackInfo.stackToken, outBounds);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to resize PiP on display rotation", e);
+240 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.pip;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;

import android.content.ComponentName;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IPinnedStackController;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
 * Unit tests against {@link PipBoundsHandler}, including but not limited to:
 * - default/movement bounds
 * - save/restore PiP position on application lifecycle
 * - save/restore PiP position on screen rotation
 */
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class PipBoundsHandlerTest extends SysuiTestCase {
    private static final int ROUNDING_ERROR_MARGIN = 10;

    private PipBoundsHandler mPipBoundsHandler;
    private DisplayInfo mDefaultDisplayInfo;
    private Rect mDefaultDisplayRect;

    @Mock
    private IPinnedStackController mPinnedStackController;

    @Before
    public void setUp() throws Exception {
        mPipBoundsHandler = new PipBoundsHandler(mContext);
        MockitoAnnotations.initMocks(this);
        initializeMockResources();

        mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo);
        mPipBoundsHandler.setPinnedStackController(mPinnedStackController);
    }

    private void initializeMockResources() {
        final TestableResources res = mContext.getOrCreateTestableResources();
        res.addOverride(
                com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio, 1f);
        res.addOverride(
                com.android.internal.R.integer.config_defaultPictureInPictureGravity,
                Gravity.END | Gravity.BOTTOM);
        res.addOverride(
                com.android.internal.R.dimen.default_minimal_size_pip_resizable_task, 100);
        res.addOverride(
                com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets,
                "16x16");
        res.addOverride(
                com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio, 0.5f);
        res.addOverride(
                com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio, 2f);

        mDefaultDisplayInfo = new DisplayInfo();
        mDefaultDisplayInfo.displayId = 1;
        mDefaultDisplayInfo.logicalWidth = 1000;
        mDefaultDisplayInfo.logicalHeight = 1500;
        mDefaultDisplayRect = new Rect(0, 0,
                mDefaultDisplayInfo.logicalWidth, mDefaultDisplayInfo.logicalHeight);
    }

    @Test
    public void setShelfHeight_offsetBounds() throws Exception {
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);
        final int shelfHeight = 100;

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect lastPosition = destinationBounds.getValue();
        // Reset the pinned stack controller since we will do another verify later on
        reset(mPinnedStackController);

        mPipBoundsHandler.setShelfHeight(true, shelfHeight);
        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        lastPosition.offset(0, -shelfHeight);
        assertBoundsWithMargin("PiP bounds offset by shelf height",
                lastPosition, destinationBounds.getValue());
    }

    @Test
    public void onImeVisibilityChanged_offsetBounds() throws Exception {
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);
        final int imeHeight = 100;

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect lastPosition = destinationBounds.getValue();
        // Reset the pinned stack controller since we will do another verify later on
        reset(mPinnedStackController);

        mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight);
        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        lastPosition.offset(0, -imeHeight);
        assertBoundsWithMargin("PiP bounds offset by IME height",
                lastPosition, destinationBounds.getValue());
    }

    @Test
    public void onPrepareAnimation_startAnimation() throws Exception {
        final Rect sourceRectHint = new Rect(100, 100, 200, 200);
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);

        mPipBoundsHandler.onPrepareAnimation(sourceRectHint, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), eq(sourceRectHint), anyInt());
        final Rect capturedDestinationBounds = destinationBounds.getValue();
        assertFalse("Destination bounds is not empty",
                capturedDestinationBounds.isEmpty());
        assertBoundsWithMargin("Destination bounds within Display",
                mDefaultDisplayRect, capturedDestinationBounds);
    }

    @Test
    public void onSaveReentryBounds_restoreLastPosition() throws Exception {
        final ComponentName componentName = new ComponentName(mContext, "component1");
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect lastPosition = destinationBounds.getValue();
        lastPosition.offset(0, -100);
        mPipBoundsHandler.onSaveReentryBounds(componentName, lastPosition);
        // Reset the pinned stack controller since we will do another verify later on
        reset(mPinnedStackController);

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        assertBoundsWithMargin("Last position is restored",
                lastPosition, destinationBounds.getValue());
    }

    @Test
    public void onResetReentryBounds_componentMatch_useDefaultBounds() throws Exception {
        final ComponentName componentName = new ComponentName(mContext, "component1");
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect defaultBounds = new Rect(destinationBounds.getValue());
        final Rect newBounds = new Rect(defaultBounds);
        newBounds.offset(0, -100);
        mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds);
        // Reset the pinned stack controller since we will do another verify later on
        reset(mPinnedStackController);

        mPipBoundsHandler.onResetReentryBounds(componentName);
        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect actualBounds = destinationBounds.getValue();
        assertBoundsWithMargin("Use default bounds", defaultBounds, actualBounds);
    }

    @Test
    public void onResetReentryBounds_componentMismatch_restoreLastPosition() throws Exception {
        final ComponentName componentName = new ComponentName(mContext, "component1");
        final ArgumentCaptor<Rect> destinationBounds = ArgumentCaptor.forClass(Rect.class);

        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect defaultBounds = new Rect(destinationBounds.getValue());
        final Rect newBounds = new Rect(defaultBounds);
        newBounds.offset(0, -100);
        mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds);
        // Reset the pinned stack controller since we will do another verify later on
        reset(mPinnedStackController);

        mPipBoundsHandler.onResetReentryBounds(new ComponentName(mContext, "component2"));
        mPipBoundsHandler.onPrepareAnimation(null, 1f, null);

        verify(mPinnedStackController).startAnimation(
                destinationBounds.capture(), isNull(), anyInt());
        final Rect actualBounds = destinationBounds.getValue();
        assertBoundsWithMargin("Last position is restored", newBounds, actualBounds);
    }

    private void assertBoundsWithMargin(String msg, Rect expected, Rect actual) {
        expected.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN);
        assertTrue(msg, expected.contains(actual));
    }
}
+0 −2
Original line number Diff line number Diff line
@@ -112,7 +112,6 @@ import static com.android.server.wm.DisplayContentProto.ID;
import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS;
import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.STACKS;
@@ -2779,7 +2778,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            stack.dumpDebugInnerStackOnly(proto, STACKS, logLevel);
        }
        mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
        mPinnedStackControllerLocked.dumpDebug(proto, PINNED_STACK_CONTROLLER);
        for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
            final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i);
            windowToken.dumpDebug(proto, ABOVE_APP_WINDOWS, logLevel);
Loading