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

Commit b0038aa9 authored by Hongwei Wang's avatar Hongwei Wang
Browse files

Unit test for PipSurfaceTransactionHelper

- Cleanup the unused code path in pip2.PipSurfaceTransactionHelper
- Add basic unit test cases for pip2.PipSurfaceTransactionHelper

Flag: com.android.wm.shell.enable_pip2
Bug: 376133026
Test: atest WMShellUnitTests:PipSurfaceTransactionHelperTest
Change-Id: Ia938507883ea8d6b2b460a2f33805de880c8217c
parent b52b31fe
Loading
Loading
Loading
Loading
+2 −108
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.wm.shell.pip2;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.Choreographer;
import android.view.SurfaceControl;

@@ -29,98 +28,18 @@ import com.android.wm.shell.R;
 * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
 */
public class PipSurfaceTransactionHelper {
    /** for {@link #scale(SurfaceControl.Transaction, SurfaceControl, Rect, Rect)} operation */
    private final Matrix mTmpTransform = new Matrix();
    private final float[] mTmpFloat9 = new float[9];
    private final RectF mTmpSourceRectF = new RectF();
    private final RectF mTmpDestinationRectF = new RectF();
    private final Rect mTmpDestinationRect = new Rect();

    private int mCornerRadius;
    private int mShadowRadius;
    private final int mCornerRadius;
    private final int mShadowRadius;

    public PipSurfaceTransactionHelper(Context context) {
        onDensityOrFontScaleChanged(context);
    }

    /**
     * Called when display size or font size of settings changed
     *
     * @param context the current context
     */
    public void onDensityOrFontScaleChanged(Context context) {
        mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
        mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
    }

    /**
     * Operates the alpha on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
            float alpha) {
        tx.setAlpha(leash, alpha);
        return this;
    }

    /**
     * Operates the crop (and position) on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect destinationBounds) {
        tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
                .setPosition(leash, destinationBounds.left, destinationBounds.top);
        return this;
    }

    /**
     * Operates the scale (setMatrix) on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect sourceBounds, Rect destinationBounds) {
        mTmpDestinationRectF.set(destinationBounds);
        return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */);
    }

    /**
     * Operates the scale (setMatrix) on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect sourceBounds, RectF destinationBounds) {
        return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */);
    }

    /**
     * Operates the scale (setMatrix) on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect sourceBounds, Rect destinationBounds, float degrees) {
        mTmpDestinationRectF.set(destinationBounds);
        return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees);
    }

    /**
     * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation.
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect sourceBounds, RectF destinationBounds, float degrees) {
        mTmpSourceRectF.set(sourceBounds);
        // We want the matrix to position the surface relative to the screen coordinates so offset
        // the source to 0,0
        mTmpSourceRectF.offsetTo(0, 0);
        mTmpDestinationRectF.set(destinationBounds);
        mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
        mTmpTransform.postRotate(degrees,
                mTmpDestinationRectF.centerX(), mTmpDestinationRectF.centerY());
        tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
        return this;
    }

    /**
     * Operates the scale (setMatrix) on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
@@ -204,19 +123,6 @@ public class PipSurfaceTransactionHelper {
        return this;
    }

    /**
     * Resets the scale (setMatrix) on a given transaction and leash if there's any
     *
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx,
            SurfaceControl leash,
            Rect destinationBounds) {
        tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
                .setPosition(leash, destinationBounds.left, destinationBounds.top);
        return this;
    }

    /**
     * Operates the round corner radius on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
@@ -227,18 +133,6 @@ public class PipSurfaceTransactionHelper {
        return this;
    }

    /**
     * Operates the round corner radius on a given transaction and leash, scaled by bounds
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
     */
    public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect fromBounds, Rect toBounds) {
        final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
                / Math.hypot(toBounds.width(), toBounds.height()));
        tx.setCornerRadius(leash, mCornerRadius * scale);
        return this;
    }

    /**
     * Operates the shadow radius on a given transaction and leash
     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+107 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.wm.shell.pip2;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.SurfaceControl;

import androidx.test.filters.SmallTest;

import com.android.wm.shell.R;

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

/**
 * Unit test against {@link PipSurfaceTransactionHelper}.
 */
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class PipSurfaceTransactionHelperTest {

    private static final int CORNER_RADIUS = 10;
    private static final int SHADOW_RADIUS = 20;

    @Mock private Context mMockContext;
    @Mock private Resources mMockResources;
    @Mock private SurfaceControl.Transaction mMockTransaction;

    private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
    private SurfaceControl mTestLeash;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        when(mMockContext.getResources()).thenReturn(mMockResources);
        when(mMockResources.getDimensionPixelSize(eq(R.dimen.pip_corner_radius)))
                .thenReturn(CORNER_RADIUS);
        when(mMockResources.getDimensionPixelSize(eq(R.dimen.pip_shadow_radius)))
                .thenReturn(SHADOW_RADIUS);
        when(mMockTransaction.setCornerRadius(any(SurfaceControl.class), anyFloat()))
                .thenReturn(mMockTransaction);
        when(mMockTransaction.setShadowRadius(any(SurfaceControl.class), anyFloat()))
                .thenReturn(mMockTransaction);

        mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(mMockContext);
        mTestLeash = new SurfaceControl.Builder()
                .setContainerLayer()
                .setName("PipSurfaceTransactionHelperTest")
                .setCallsite("PipSurfaceTransactionHelperTest")
                .build();
    }

    @Test
    public void round_doNotApply_setZeroCornerRadius() {
        mPipSurfaceTransactionHelper.round(mMockTransaction, mTestLeash, false /* apply */);

        verify(mMockTransaction).setCornerRadius(eq(mTestLeash), eq(0f));
    }

    @Test
    public void round_doApply_setExactCornerRadius() {
        mPipSurfaceTransactionHelper.round(mMockTransaction, mTestLeash, true /* apply */);

        verify(mMockTransaction).setCornerRadius(eq(mTestLeash), eq((float) CORNER_RADIUS));
    }

    @Test
    public void shadow_doNotApply_setZeroShadowRadius() {
        mPipSurfaceTransactionHelper.shadow(mMockTransaction, mTestLeash, false /* apply */);

        verify(mMockTransaction).setShadowRadius(eq(mTestLeash), eq(0f));
    }

    @Test
    public void shadow_doApply_setExactShadowRadius() {
        mPipSurfaceTransactionHelper.shadow(mMockTransaction, mTestLeash, true /* apply */);

        verify(mMockTransaction).setShadowRadius(eq(mTestLeash), eq((float) SHADOW_RADIUS));
    }
}