Loading services/core/java/com/android/server/wm/Letterbox.java +27 −28 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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() { Loading @@ -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); Loading @@ -201,7 +200,7 @@ public class Letterbox { } public boolean needsApplySurfaceChanges() { return !mSurfaceFrame.equals(mLayoutFrame); return !mSurfaceFrameRelative.equals(mLayoutFrameRelative); } } } services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java 0 → 100644 +122 −0 Original line number Diff line number Diff line /* * 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; } } } Loading
services/core/java/com/android/server/wm/Letterbox.java +27 −28 Original line number Diff line number Diff line Loading @@ -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); } Loading Loading @@ -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() { Loading @@ -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); Loading @@ -201,7 +200,7 @@ public class Letterbox { } public boolean needsApplySurfaceChanges() { return !mSurfaceFrame.equals(mLayoutFrame); return !mSurfaceFrameRelative.equals(mLayoutFrameRelative); } } }
services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java 0 → 100644 +122 −0 Original line number Diff line number Diff line /* * 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; } } }