Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java +2 −108 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelperTest.java 0 → 100644 +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)); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java +2 −108 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelperTest.java 0 → 100644 +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)); } }