diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/Letterbox.java | 55 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java | 122 |
2 files changed, 149 insertions, 28 deletions
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 33ff19415089..434084cc1f3d 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -64,15 +64,11 @@ public class Letterbox { public void layout(Rect outer, Rect inner, Point surfaceOrigin) { mOuter.set(outer); mInner.set(inner); - mOuter.offset(-surfaceOrigin.x, -surfaceOrigin.y); - mInner.offset(-surfaceOrigin.x, -surfaceOrigin.y); - outer = mOuter; - inner = mInner; - - mTop.layout(outer.left, outer.top, inner.right, inner.top); - mLeft.layout(outer.left, inner.top, inner.left, outer.bottom); - mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom); - mRight.layout(inner.right, outer.top, outer.right, inner.bottom); + + mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin); + mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin); + mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin); + mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin); } @@ -137,20 +133,18 @@ public class Letterbox { private final String mType; private SurfaceControl mSurface; - private final Rect mSurfaceFrame = new Rect(); - private final Rect mLayoutFrame = new Rect(); + private final Rect mSurfaceFrameRelative = new Rect(); + private final Rect mLayoutFrameGlobal = new Rect(); + private final Rect mLayoutFrameRelative = new Rect(); public LetterboxSurface(String type) { mType = type; } - public void layout(int left, int top, int right, int bottom) { - if (mLayoutFrame.left == left && mLayoutFrame.top == top - && mLayoutFrame.right == right && mLayoutFrame.bottom == bottom) { - // Nothing changed. - return; - } - mLayoutFrame.set(left, top, right, bottom); + public void layout(int left, int top, int right, int bottom, Point surfaceOrigin) { + mLayoutFrameGlobal.set(left, top, right, bottom); + mLayoutFrameRelative.set(mLayoutFrameGlobal); + mLayoutFrameRelative.offset(-surfaceOrigin.x, -surfaceOrigin.y); } private void createSurface() { @@ -168,32 +162,37 @@ public class Letterbox { } public int getWidth() { - return Math.max(0, mLayoutFrame.width()); + return Math.max(0, mLayoutFrameGlobal.width()); } public int getHeight() { - return Math.max(0, mLayoutFrame.height()); + return Math.max(0, mLayoutFrameGlobal.height()); } + /** + * Returns if the given {@code rect} overlaps with this letterbox piece. + * @param rect the area to check for overlap in global coordinates + */ public boolean isOverlappingWith(Rect rect) { - if (getWidth() <= 0 || getHeight() <= 0) { + if (mLayoutFrameGlobal.isEmpty()) { return false; } - return Rect.intersects(rect, mLayoutFrame); + return Rect.intersects(rect, mLayoutFrameGlobal); } public void applySurfaceChanges(SurfaceControl.Transaction t) { - if (mSurfaceFrame.equals(mLayoutFrame)) { + if (mSurfaceFrameRelative.equals(mLayoutFrameRelative)) { // Nothing changed. return; } - mSurfaceFrame.set(mLayoutFrame); - if (!mSurfaceFrame.isEmpty()) { + mSurfaceFrameRelative.set(mLayoutFrameRelative); + if (!mSurfaceFrameRelative.isEmpty()) { if (mSurface == null) { createSurface(); } - t.setPosition(mSurface, mSurfaceFrame.left, mSurfaceFrame.top); - t.setWindowCrop(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height()); + t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top); + t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(), + mSurfaceFrameRelative.height()); t.show(mSurface); } else if (mSurface != null) { t.hide(mSurface); @@ -201,7 +200,7 @@ public class Letterbox { } public boolean needsApplySurfaceChanges() { - return !mSurfaceFrame.equals(mLayoutFrame); + return !mSurfaceFrameRelative.equals(mLayoutFrameRelative); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java new file mode 100644 index 000000000000..c52c8d7eb7bd --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 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.server.wm; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.graphics.Point; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.view.SurfaceControl; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; + +import java.util.function.Supplier; + +@SmallTest +@Presubmit +public class LetterboxTest { + + Letterbox mLetterbox; + SurfaceControlMocker mSurfaces; + SurfaceControl.Transaction mTransaction; + + @Before + public void setUp() throws Exception { + mSurfaces = new SurfaceControlMocker(); + mLetterbox = new Letterbox(mSurfaces); + mTransaction = mock(SurfaceControl.Transaction.class); + } + + @Test + public void testOverlappingWith_usesGlobalCoordinates() { + mLetterbox.layout(new Rect(0, 0, 10, 50), new Rect(0, 2, 10, 45), new Point(1000, 2000)); + assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1))); + } + + @Test + public void testSurfaceOrigin_applied() { + mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); + mLetterbox.applySurfaceChanges(mTransaction); + verify(mTransaction).setPosition(mSurfaces.top, -1000, -2000); + } + + @Test + public void testSurfaceOrigin_changeCausesReapply() { + mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000)); + mLetterbox.applySurfaceChanges(mTransaction); + clearInvocations(mTransaction); + mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0)); + assertTrue(mLetterbox.needsApplySurfaceChanges()); + mLetterbox.applySurfaceChanges(mTransaction); + verify(mTransaction).setPosition(mSurfaces.top, 0, 0); + } + + class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> { + private SurfaceControl.Builder mLeftBuilder; + public SurfaceControl left; + private SurfaceControl.Builder mTopBuilder; + public SurfaceControl top; + private SurfaceControl.Builder mRightBuilder; + public SurfaceControl right; + private SurfaceControl.Builder mBottomBuilder; + public SurfaceControl bottom; + + @Override + public SurfaceControl.Builder get() { + final SurfaceControl.Builder builder = mock(SurfaceControl.Builder.class, + InvocationOnMock::getMock); + when(builder.setName(anyString())).then((i) -> { + if (((String) i.getArgument(0)).contains("left")) { + mLeftBuilder = (SurfaceControl.Builder) i.getMock(); + } else if (((String) i.getArgument(0)).contains("top")) { + mTopBuilder = (SurfaceControl.Builder) i.getMock(); + } else if (((String) i.getArgument(0)).contains("right")) { + mRightBuilder = (SurfaceControl.Builder) i.getMock(); + } else if (((String) i.getArgument(0)).contains("bottom")) { + mBottomBuilder = (SurfaceControl.Builder) i.getMock(); + } + return i.getMock(); + }); + + doAnswer((i) -> { + final SurfaceControl control = mock(SurfaceControl.class); + if (i.getMock() == mLeftBuilder) { + left = control; + } else if (i.getMock() == mTopBuilder) { + top = control; + } else if (i.getMock() == mRightBuilder) { + right = control; + } else if (i.getMock() == mBottomBuilder) { + bottom = control; + } + return control; + }).when(builder).build(); + return builder; + } + } +} |