Loading packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java +7 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,13 @@ public class ScrollCaptureClient { */ int getMaxTiles(); /** * @return the maximum combined capture height for this session, in pixels. */ default int getMaxHeight() { return getMaxTiles() * getTileHeight(); } /** * @return the height of each image tile */ Loading packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +6 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.view.ScrollCaptureResponse; import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.concurrent.futures.CallbackToFutureAdapter.Completer; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult; import com.android.systemui.screenshot.ScrollCaptureClient.Session; Loading Loading @@ -139,6 +140,11 @@ public class ScrollCaptureController { mImageTileSet = imageTileSet; } @VisibleForTesting float getTargetTopSizeRatio() { return IDEAL_PORTION_ABOVE; } /** * Run scroll capture. Performs a batch capture, collecting image tiles. * Loading packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.screenshot; import static android.util.MathUtils.constrain; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static java.lang.Math.abs; import static java.lang.Math.max; import static java.lang.Math.min; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.media.Image; import android.util.Log; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; /** * A flexible test double for {@link ScrollCaptureClient.Session}. * <p> * FakeSession provides the ability to emulate both the available scrollable content range as well * as the current visible bounds. Visible bounds may vary because the target view itself may be * slid vertically during capture, with portions may become clipped by parent views. This scenario * frequently occurs with UIs constructed from nested scrolling views or collapsing headers. */ class FakeSession implements ScrollCaptureClient.Session { private static final String TAG = "FakeSession"; // Available range of content private final Rect mAvailable; /** bounds for scrollDelta (y), range with bottom adjusted to account for page height. */ private final Rect mAvailableTop; private final Rect mVisiblePage; private final int mTileHeight; private final int mMaxTiles; private int mScrollDelta; private int mPageHeight; FakeSession(int pageHeight, float maxPages, int tileHeight, int visiblePageTop, int visiblePageBottom, int availableTop, int availableBottom) { mPageHeight = pageHeight; mTileHeight = tileHeight; mAvailable = new Rect(0, availableTop, getPageWidth(), availableBottom); mAvailableTop = new Rect(mAvailable); mAvailableTop.inset(0, 0, 0, pageHeight); mVisiblePage = new Rect(0, visiblePageTop, getPageWidth(), visiblePageBottom); mMaxTiles = (int) Math.ceil((pageHeight * maxPages) / mTileHeight); } private static Image mockImage() { Image image = mock(Image.class); when(image.getHardwareBuffer()).thenReturn(mock(HardwareBuffer.class)); return image; } public int getScrollDelta() { return mScrollDelta; } @Override public ListenableFuture<ScrollCaptureClient.CaptureResult> requestTile(int requestedTop) { Rect requested = new Rect(0, requestedTop, getPageWidth(), requestedTop + getTileHeight()); Log.d(TAG, "requested: " + requested); Rect page = new Rect(0, 0, getPageWidth(), mPageHeight); page.offset(0, mScrollDelta); Log.d(TAG, "page: " + page); // Simulate behavior from lower levels by replicating 'requestChildRectangleOnScreen' if (!page.contains(requested)) { Log.d(TAG, "requested not within page, scrolling"); // distance+direction needed to scroll to align each edge of request with // corresponding edge of the page int distTop = requested.top - page.top; // positive means already visible int distBottom = requested.bottom - page.bottom; // negative means already visible Log.d(TAG, "distTop = " + distTop); Log.d(TAG, "distBottom = " + distBottom); boolean scrollUp = false; if (distTop < 0 && distBottom > 0) { scrollUp = abs(distTop) < distBottom; } else if (distTop < 0) { scrollUp = true; } // determine which edges are currently clipped if (scrollUp) { Log.d(TAG, "trying to scroll up by " + -distTop + " px"); // need to scroll up to align top edge to visible-top mScrollDelta += distTop; Log.d(TAG, "new scrollDelta = " + mScrollDelta); } else { Log.d(TAG, "trying to scroll down by " + distBottom + " px"); // scroll down to align bottom edge with visible bottom, but keep top visible int topEdgeDistance = max(0, requestedTop - page.top); mScrollDelta += min(distBottom, topEdgeDistance); Log.d(TAG, "new scrollDelta = " + mScrollDelta); } // Clamp to available content mScrollDelta = constrain(mScrollDelta, mAvailableTop.top, mAvailableTop.bottom); Log.d(TAG, "scrollDelta, adjusted to available range = " + mScrollDelta); // Reset to apply a changed scroll delta possibly. page.offsetTo(0, 0); page.offset(0, mScrollDelta); Log.d(TAG, "page (after scroll): " + page); Log.d(TAG, "requested (after scroll): " + requested); } Log.d(TAG, "mVisiblePage = " + mVisiblePage); Log.d(TAG, "scrollDelta = " + mScrollDelta); Rect target = new Rect(requested); Rect visible = new Rect(mVisiblePage); visible.offset(0, mScrollDelta); Log.d(TAG, "target: " + target); Log.d(TAG, "visible: " + visible); // if any of the requested rect is available to scroll into the view: if (target.intersect(page) && target.intersect(visible)) { Log.d(TAG, "returning captured = " + target); ScrollCaptureClient.CaptureResult result = new ScrollCaptureClient.CaptureResult(mockImage(), requested, target); return immediateFuture(result); } Log.d(TAG, "no part of requested rect is within page, returning empty"); ScrollCaptureClient.CaptureResult result = new ScrollCaptureClient.CaptureResult(null, requested, new Rect()); return immediateFuture(result); } @Override public int getMaxTiles() { return mMaxTiles; } @Override public int getTileHeight() { return mTileHeight; } @Override public int getPageWidth() { return 100; } @Override public int getPageHeight() { return mPageHeight; } @Override public Rect getWindowBounds() { throw new IllegalStateException("Not implemented"); } @Override public ListenableFuture<Void> end() { return Futures.immediateVoidFuture(); } @Override public void release() { } } packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java 0 → 100644 +293 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.screenshot; import static com.google.common.util.concurrent.Futures.getUnchecked; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for {@link FakeSession}, a a test double for a ScrollCaptureClient.Session. * <p> * These tests verify a single tile request behaves similarly to a live scroll capture * client/connection. */ @SmallTest @RunWith(AndroidTestingRunner.class) public class FakeSessionTest extends SysuiTestCase { @Test public void testMaxTiles() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.25f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); // (pageHeight * maxPages) / tileHeight assertEquals("getMaxTiles()", 23, session.getMaxTiles()); } @Test public void testNonEmptyResult_hasImage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 1.0f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ 0, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertNotNull("result.image", result.image); assertNotNull("result.image.getHardwareBuffer()", result.image.getHardwareBuffer()); } @Test public void testEmptyResult_hasNullImage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 1.0f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ 0, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100)); assertNull("result.image", result.image); } @Test public void testCaptureAtZero() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertEquals("requested top", 0, result.requested.top); assertEquals("requested bottom", 10, result.requested.bottom); assertEquals("captured top", 0, result.captured.top); assertEquals("captured bottom", 10, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testCaptureAtPageBottom() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(90)); assertEquals("requested top", 90, result.requested.top); assertEquals("requested bottom", 100, result.requested.bottom); assertEquals("captured top", 90, result.captured.top); assertEquals("captured bottom", 100, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testCaptureFromPreviousPage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100)); assertEquals("requested top", -100, result.requested.top); assertEquals("requested bottom", -90, result.requested.bottom); assertEquals("captured top", -100, result.captured.top); assertEquals("captured bottom", -90, result.captured.bottom); assertEquals("scroll delta", -100, session.getScrollDelta()); } @Test public void testCaptureFromNextPage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(150)); assertEquals("requested top", 150, result.requested.top); assertEquals("requested bottom", 160, result.requested.bottom); assertEquals("captured top", 150, result.captured.top); assertEquals("captured bottom", 160, result.captured.bottom); assertEquals("scroll delta", 60, session.getScrollDelta()); } @Test public void testCaptureTopPartiallyUnavailable() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-125)); assertEquals("requested top", -125, result.requested.top); assertEquals("requested bottom", -75, result.requested.bottom); assertEquals("captured top", -100, result.captured.top); assertEquals("captured bottom", -75, result.captured.bottom); assertEquals("scroll delta", -100, session.getScrollDelta()); } @Test public void testCaptureBottomPartiallyUnavailable() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(75)); assertEquals("requested top", 75, result.requested.top); assertEquals("requested bottom", 125, result.requested.bottom); assertEquals("captured top", 75, result.captured.top); assertEquals("captured bottom", 100, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } /** * Set visiblePageTop > 0 to cause the returned request's top edge to be cropped. */ @Test public void testCaptureTopPartiallyInvisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 25, // <<-- /* visiblePageBottom */ 100, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150)); assertEquals("requested top", -150, result.requested.top); assertEquals("requested bottom", -100, result.requested.bottom); assertEquals("captured top", -125, result.captured.top); assertEquals("captured bottom", -100, result.captured.bottom); assertEquals("scroll delta", -150, session.getScrollDelta()); } /** * Set visiblePageBottom < pageHeight to cause the returned request's bottom edge to be cropped. */ @Test public void testCaptureBottomPartiallyInvisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 75, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(50)); assertEquals("requested top", 50, result.requested.top); assertEquals("requested bottom", 100, result.requested.bottom); assertEquals("captured top", 50, result.captured.top); assertEquals("captured bottom", 75, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testEmptyResult_aboveAvailableTop() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3.0f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 200); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150)); assertTrue("captured rect is empty", result.captured.isEmpty()); } @Test public void testEmptyResult_belowAvailableBottom() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3.0f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 200); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(200)); assertTrue("captured rect is empty", result.captured.isEmpty()); } @Test public void testEmptyResult_notVisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 60, // <<--- /* visiblePageBottom */ 0, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertEquals("requested top", 0, result.requested.top); assertEquals("requested bottom", 50, result.requested.bottom); assertEquals("captured top", 0, result.captured.top); assertEquals("captured bottom", 0, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } } packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java +156 −153 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java +7 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,13 @@ public class ScrollCaptureClient { */ int getMaxTiles(); /** * @return the maximum combined capture height for this session, in pixels. */ default int getMaxHeight() { return getMaxTiles() * getTileHeight(); } /** * @return the height of each image tile */ Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java +6 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.view.ScrollCaptureResponse; import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.concurrent.futures.CallbackToFutureAdapter.Completer; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult; import com.android.systemui.screenshot.ScrollCaptureClient.Session; Loading Loading @@ -139,6 +140,11 @@ public class ScrollCaptureController { mImageTileSet = imageTileSet; } @VisibleForTesting float getTargetTopSizeRatio() { return IDEAL_PORTION_ABOVE; } /** * Run scroll capture. Performs a batch capture, collecting image tiles. * Loading
packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.screenshot; import static android.util.MathUtils.constrain; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static java.lang.Math.abs; import static java.lang.Math.max; import static java.lang.Math.min; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.media.Image; import android.util.Log; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; /** * A flexible test double for {@link ScrollCaptureClient.Session}. * <p> * FakeSession provides the ability to emulate both the available scrollable content range as well * as the current visible bounds. Visible bounds may vary because the target view itself may be * slid vertically during capture, with portions may become clipped by parent views. This scenario * frequently occurs with UIs constructed from nested scrolling views or collapsing headers. */ class FakeSession implements ScrollCaptureClient.Session { private static final String TAG = "FakeSession"; // Available range of content private final Rect mAvailable; /** bounds for scrollDelta (y), range with bottom adjusted to account for page height. */ private final Rect mAvailableTop; private final Rect mVisiblePage; private final int mTileHeight; private final int mMaxTiles; private int mScrollDelta; private int mPageHeight; FakeSession(int pageHeight, float maxPages, int tileHeight, int visiblePageTop, int visiblePageBottom, int availableTop, int availableBottom) { mPageHeight = pageHeight; mTileHeight = tileHeight; mAvailable = new Rect(0, availableTop, getPageWidth(), availableBottom); mAvailableTop = new Rect(mAvailable); mAvailableTop.inset(0, 0, 0, pageHeight); mVisiblePage = new Rect(0, visiblePageTop, getPageWidth(), visiblePageBottom); mMaxTiles = (int) Math.ceil((pageHeight * maxPages) / mTileHeight); } private static Image mockImage() { Image image = mock(Image.class); when(image.getHardwareBuffer()).thenReturn(mock(HardwareBuffer.class)); return image; } public int getScrollDelta() { return mScrollDelta; } @Override public ListenableFuture<ScrollCaptureClient.CaptureResult> requestTile(int requestedTop) { Rect requested = new Rect(0, requestedTop, getPageWidth(), requestedTop + getTileHeight()); Log.d(TAG, "requested: " + requested); Rect page = new Rect(0, 0, getPageWidth(), mPageHeight); page.offset(0, mScrollDelta); Log.d(TAG, "page: " + page); // Simulate behavior from lower levels by replicating 'requestChildRectangleOnScreen' if (!page.contains(requested)) { Log.d(TAG, "requested not within page, scrolling"); // distance+direction needed to scroll to align each edge of request with // corresponding edge of the page int distTop = requested.top - page.top; // positive means already visible int distBottom = requested.bottom - page.bottom; // negative means already visible Log.d(TAG, "distTop = " + distTop); Log.d(TAG, "distBottom = " + distBottom); boolean scrollUp = false; if (distTop < 0 && distBottom > 0) { scrollUp = abs(distTop) < distBottom; } else if (distTop < 0) { scrollUp = true; } // determine which edges are currently clipped if (scrollUp) { Log.d(TAG, "trying to scroll up by " + -distTop + " px"); // need to scroll up to align top edge to visible-top mScrollDelta += distTop; Log.d(TAG, "new scrollDelta = " + mScrollDelta); } else { Log.d(TAG, "trying to scroll down by " + distBottom + " px"); // scroll down to align bottom edge with visible bottom, but keep top visible int topEdgeDistance = max(0, requestedTop - page.top); mScrollDelta += min(distBottom, topEdgeDistance); Log.d(TAG, "new scrollDelta = " + mScrollDelta); } // Clamp to available content mScrollDelta = constrain(mScrollDelta, mAvailableTop.top, mAvailableTop.bottom); Log.d(TAG, "scrollDelta, adjusted to available range = " + mScrollDelta); // Reset to apply a changed scroll delta possibly. page.offsetTo(0, 0); page.offset(0, mScrollDelta); Log.d(TAG, "page (after scroll): " + page); Log.d(TAG, "requested (after scroll): " + requested); } Log.d(TAG, "mVisiblePage = " + mVisiblePage); Log.d(TAG, "scrollDelta = " + mScrollDelta); Rect target = new Rect(requested); Rect visible = new Rect(mVisiblePage); visible.offset(0, mScrollDelta); Log.d(TAG, "target: " + target); Log.d(TAG, "visible: " + visible); // if any of the requested rect is available to scroll into the view: if (target.intersect(page) && target.intersect(visible)) { Log.d(TAG, "returning captured = " + target); ScrollCaptureClient.CaptureResult result = new ScrollCaptureClient.CaptureResult(mockImage(), requested, target); return immediateFuture(result); } Log.d(TAG, "no part of requested rect is within page, returning empty"); ScrollCaptureClient.CaptureResult result = new ScrollCaptureClient.CaptureResult(null, requested, new Rect()); return immediateFuture(result); } @Override public int getMaxTiles() { return mMaxTiles; } @Override public int getTileHeight() { return mTileHeight; } @Override public int getPageWidth() { return 100; } @Override public int getPageHeight() { return mPageHeight; } @Override public Rect getWindowBounds() { throw new IllegalStateException("Not implemented"); } @Override public ListenableFuture<Void> end() { return Futures.immediateVoidFuture(); } @Override public void release() { } }
packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java 0 → 100644 +293 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.screenshot; import static com.google.common.util.concurrent.Futures.getUnchecked; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for {@link FakeSession}, a a test double for a ScrollCaptureClient.Session. * <p> * These tests verify a single tile request behaves similarly to a live scroll capture * client/connection. */ @SmallTest @RunWith(AndroidTestingRunner.class) public class FakeSessionTest extends SysuiTestCase { @Test public void testMaxTiles() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.25f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); // (pageHeight * maxPages) / tileHeight assertEquals("getMaxTiles()", 23, session.getMaxTiles()); } @Test public void testNonEmptyResult_hasImage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 1.0f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ 0, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertNotNull("result.image", result.image); assertNotNull("result.image.getHardwareBuffer()", result.image.getHardwareBuffer()); } @Test public void testEmptyResult_hasNullImage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 1.0f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ 0, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100)); assertNull("result.image", result.image); } @Test public void testCaptureAtZero() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertEquals("requested top", 0, result.requested.top); assertEquals("requested bottom", 10, result.requested.bottom); assertEquals("captured top", 0, result.captured.top); assertEquals("captured bottom", 10, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testCaptureAtPageBottom() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(90)); assertEquals("requested top", 90, result.requested.top); assertEquals("requested bottom", 100, result.requested.bottom); assertEquals("captured top", 90, result.captured.top); assertEquals("captured bottom", 100, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testCaptureFromPreviousPage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100)); assertEquals("requested top", -100, result.requested.top); assertEquals("requested bottom", -90, result.requested.bottom); assertEquals("captured top", -100, result.captured.top); assertEquals("captured bottom", -90, result.captured.bottom); assertEquals("scroll delta", -100, session.getScrollDelta()); } @Test public void testCaptureFromNextPage() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 2.5f, /* tileHeight */ 10, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -250, /* availableBottom */ 250); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(150)); assertEquals("requested top", 150, result.requested.top); assertEquals("requested bottom", 160, result.requested.bottom); assertEquals("captured top", 150, result.captured.top); assertEquals("captured bottom", 160, result.captured.bottom); assertEquals("scroll delta", 60, session.getScrollDelta()); } @Test public void testCaptureTopPartiallyUnavailable() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-125)); assertEquals("requested top", -125, result.requested.top); assertEquals("requested bottom", -75, result.requested.bottom); assertEquals("captured top", -100, result.captured.top); assertEquals("captured bottom", -75, result.captured.bottom); assertEquals("scroll delta", -100, session.getScrollDelta()); } @Test public void testCaptureBottomPartiallyUnavailable() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 100); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(75)); assertEquals("requested top", 75, result.requested.top); assertEquals("requested bottom", 125, result.requested.bottom); assertEquals("captured top", 75, result.captured.top); assertEquals("captured bottom", 100, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } /** * Set visiblePageTop > 0 to cause the returned request's top edge to be cropped. */ @Test public void testCaptureTopPartiallyInvisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 25, // <<-- /* visiblePageBottom */ 100, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150)); assertEquals("requested top", -150, result.requested.top); assertEquals("requested bottom", -100, result.requested.bottom); assertEquals("captured top", -125, result.captured.top); assertEquals("captured bottom", -100, result.captured.bottom); assertEquals("scroll delta", -150, session.getScrollDelta()); } /** * Set visiblePageBottom < pageHeight to cause the returned request's bottom edge to be cropped. */ @Test public void testCaptureBottomPartiallyInvisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 75, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(50)); assertEquals("requested top", 50, result.requested.top); assertEquals("requested bottom", 100, result.requested.bottom); assertEquals("captured top", 50, result.captured.top); assertEquals("captured bottom", 75, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } @Test public void testEmptyResult_aboveAvailableTop() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3.0f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 200); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150)); assertTrue("captured rect is empty", result.captured.isEmpty()); } @Test public void testEmptyResult_belowAvailableBottom() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3.0f, /* tileHeight */ 50, /* visiblePageTop */ 0, /* visiblePageBottom */ 100, /* availableTop */ -100, /* availableBottom */ 200); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(200)); assertTrue("captured rect is empty", result.captured.isEmpty()); } @Test public void testEmptyResult_notVisible() { FakeSession session = new FakeSession( /* pageHeight */ 100, /* maxPages */ 3f, /* tileHeight */ 50, /* visiblePageTop */ 60, // <<--- /* visiblePageBottom */ 0, /* availableTop */ -150, /* availableBottom */ 150); ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0)); assertEquals("requested top", 0, result.requested.top); assertEquals("requested bottom", 50, result.requested.bottom); assertEquals("captured top", 0, result.captured.top); assertEquals("captured bottom", 0, result.captured.bottom); assertEquals("scroll delta", 0, session.getScrollDelta()); } }
packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java +156 −153 File changed.Preview size limit exceeded, changes collapsed. Show changes