[Default Nav Transition] Remove top controls in NTP screenshot
In order to match the viewport of the webpage screenshot, this CL excludes the area of top controls of NTP and maintain the size of the screenshot. As a result, the bottom part of the screenshot will be filled with the default background color of the NTP because it is impossible to draw off-screen views in Android. Screenshot (with top controls): https://screenshot.googleplex.com/AJFcDYvXCbnvXgj.png Screen record (w/o top controls): http://screencast/cast/NDY4NTA0OTc2ODE4MTc2MHxjODkyNWE0Zi1jOQ Bug: 331814846 Change-Id: Ieb8959ad2f202b15e055346f889a73355cdc4e06 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5560151 Reviewed-by: Rakina Zata Amni <rakina@chromium.org> Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Khushal Sagar <khushalsagar@chromium.org> Commit-Queue: Lijin Shen <lazzzis@google.com> Reviewed-by: Calder Kitagawa <ckitagawa@chromium.org> Cr-Commit-Position: refs/heads/main@{#1324606}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4cc0cbba63
commit
7938c61cf2
chrome
android
java
src
org
chromium
chrome
browser
javatests
src
org
chromium
chrome
browser
browser
gesturenav
android
content
browser
web_contents
public
android
java
src
org
chromium
test
android
javatests
src
org
chromium
content_public
browser
test
@@ -429,7 +429,8 @@ final class TabWebContentsDelegateAndroidImpl extends TabWebContentsDelegateAndr
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean maybeCopyContentAreaAsBitmap(Callback<Bitmap> callback) {
|
public boolean maybeCopyContentAreaAsBitmap(Callback<Bitmap> callback) {
|
||||||
return NativePageBitmapCapturer.maybeCaptureNativeView(mTab, callback);
|
return NativePageBitmapCapturer.maybeCaptureNativeView(
|
||||||
|
mTab, callback, getTopControlsHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -45,10 +45,12 @@ import org.chromium.chrome.browser.ui.native_page.BasicSmoothTransitionDelegate;
|
|||||||
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
||||||
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||||
import org.chromium.chrome.test.util.ChromeTabUtils;
|
import org.chromium.chrome.test.util.ChromeTabUtils;
|
||||||
|
import org.chromium.chrome.test.util.NewTabPageTestUtils;
|
||||||
import org.chromium.components.embedder_support.util.UrlConstants;
|
import org.chromium.components.embedder_support.util.UrlConstants;
|
||||||
import org.chromium.content_public.browser.LoadUrlParams;
|
import org.chromium.content_public.browser.LoadUrlParams;
|
||||||
import org.chromium.content_public.browser.back_forward_transition.AnimationStage;
|
import org.chromium.content_public.browser.back_forward_transition.AnimationStage;
|
||||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||||
|
import org.chromium.content_public.browser.test.util.UiUtils;
|
||||||
import org.chromium.content_public.common.ContentUrlConstants;
|
import org.chromium.content_public.common.ContentUrlConstants;
|
||||||
import org.chromium.net.test.EmbeddedTestServer;
|
import org.chromium.net.test.EmbeddedTestServer;
|
||||||
import org.chromium.ui.base.PageTransition;
|
import org.chromium.ui.base.PageTransition;
|
||||||
@@ -66,6 +68,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
message = "crbug.com/1276402 crbug.com/345352689")
|
message = "crbug.com/1276402 crbug.com/345352689")
|
||||||
public class NavigationHandlerTest {
|
public class NavigationHandlerTest {
|
||||||
private static final String RENDERED_PAGE = "/chrome/test/data/android/navigate/simple.html";
|
private static final String RENDERED_PAGE = "/chrome/test/data/android/navigate/simple.html";
|
||||||
|
private static final String TEST_PAGE = "/chrome/test/data/android/test.html";
|
||||||
private static final boolean LEFT_EDGE = true;
|
private static final boolean LEFT_EDGE = true;
|
||||||
private static final boolean RIGHT_EDGE = false;
|
private static final boolean RIGHT_EDGE = false;
|
||||||
|
|
||||||
@@ -80,7 +83,10 @@ public class NavigationHandlerTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws InterruptedException {
|
public void setUp() throws InterruptedException {
|
||||||
mActivityTestRule.startMainActivityOnBlankPage();
|
mTestServer =
|
||||||
|
EmbeddedTestServer.createAndStartServer(
|
||||||
|
InstrumentationRegistry.getInstrumentation().getContext());
|
||||||
|
mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PAGE));
|
||||||
CompositorAnimationHandler.setTestingMode(true);
|
CompositorAnimationHandler.setTestingMode(true);
|
||||||
mNavUtils = new GestureNavigationUtils(mActivityTestRule);
|
mNavUtils = new GestureNavigationUtils(mActivityTestRule);
|
||||||
mNavigationHandler = mNavUtils.getNavigationHandler();
|
mNavigationHandler = mNavUtils.getNavigationHandler();
|
||||||
@@ -121,12 +127,12 @@ public class NavigationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@EnableFeatures({ChromeFeatureList.BACK_FORWARD_TRANSITIONS})
|
@EnableFeatures({ChromeFeatureList.BACK_FORWARD_TRANSITIONS})
|
||||||
public void testSwipeBackToNTPWithTransition() {
|
public void testSwipeBackToNTPWithTransition() throws InterruptedException {
|
||||||
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
|
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
|
||||||
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
|
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
|
||||||
mTestServer =
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
EmbeddedTestServer.createAndStartServer(
|
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
||||||
|
|
||||||
mNavUtils.swipeFromEdgeAndHold(true);
|
mNavUtils.swipeFromEdgeAndHold(true);
|
||||||
@@ -203,9 +209,6 @@ public class NavigationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testReleaseGlowWithoutPrecedingPullIgnored() {
|
public void testReleaseGlowWithoutPrecedingPullIgnored() {
|
||||||
mTestServer =
|
|
||||||
EmbeddedTestServer.createAndStartServer(
|
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
||||||
TestThreadUtils.runOnUiThreadBlocking(
|
TestThreadUtils.runOnUiThreadBlocking(
|
||||||
() -> {
|
() -> {
|
||||||
@@ -268,9 +271,6 @@ public class NavigationHandlerTest {
|
|||||||
public void testSwipeNavigateOnRenderedPage() {
|
public void testSwipeNavigateOnRenderedPage() {
|
||||||
// TODO(crbug.com/40899221): Write a test variation running with
|
// TODO(crbug.com/40899221): Write a test variation running with
|
||||||
// ChromeFeatureList.BACK_FORWARD_TRANSITIONS enabled when the feature is completed.
|
// ChromeFeatureList.BACK_FORWARD_TRANSITIONS enabled when the feature is completed.
|
||||||
mTestServer =
|
|
||||||
EmbeddedTestServer.createAndStartServer(
|
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
||||||
mActivityTestRule.loadUrl(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
|
mActivityTestRule.loadUrl(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
|
||||||
|
|
||||||
@@ -325,9 +325,6 @@ public class NavigationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testSwipeAfterDestroy() {
|
public void testSwipeAfterDestroy() {
|
||||||
mTestServer =
|
|
||||||
EmbeddedTestServer.createAndStartServer(
|
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
||||||
TestThreadUtils.runOnUiThreadBlocking(mNavigationHandler::destroy);
|
TestThreadUtils.runOnUiThreadBlocking(mNavigationHandler::destroy);
|
||||||
|
|
||||||
@@ -347,9 +344,6 @@ public class NavigationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testSwipeAfterTabDestroy() {
|
public void testSwipeAfterTabDestroy() {
|
||||||
mTestServer =
|
|
||||||
EmbeddedTestServer.createAndStartServer(
|
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
|
||||||
TestThreadUtils.runOnUiThreadBlocking(currentTab()::destroy);
|
TestThreadUtils.runOnUiThreadBlocking(currentTab()::destroy);
|
||||||
|
|
||||||
@@ -363,9 +357,6 @@ public class NavigationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testSwipeAfterDestroyActivity_NativePage() {
|
public void testSwipeAfterDestroyActivity_NativePage() {
|
||||||
mTestServer =
|
|
||||||
EmbeddedTestServer.createAndStartServer(
|
|
||||||
InstrumentationRegistry.getInstrumentation().getContext());
|
|
||||||
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
|
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
|
||||||
TestThreadUtils.runOnUiThreadBlocking(mActivityTestRule.getActivity()::finish);
|
TestThreadUtils.runOnUiThreadBlocking(mActivityTestRule.getActivity()::finish);
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
package org.chromium.chrome.browser.gesturenav;
|
package org.chromium.chrome.browser.gesturenav;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Build.VERSION_CODES;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
@@ -23,19 +24,25 @@ import org.chromium.base.test.params.ParameterAnnotations;
|
|||||||
import org.chromium.base.test.params.ParameterizedRunner;
|
import org.chromium.base.test.params.ParameterizedRunner;
|
||||||
import org.chromium.base.test.util.CallbackHelper;
|
import org.chromium.base.test.util.CallbackHelper;
|
||||||
import org.chromium.base.test.util.CommandLineFlags;
|
import org.chromium.base.test.util.CommandLineFlags;
|
||||||
|
import org.chromium.base.test.util.DisableIf;
|
||||||
import org.chromium.base.test.util.DoNotBatch;
|
import org.chromium.base.test.util.DoNotBatch;
|
||||||
import org.chromium.base.test.util.Feature;
|
import org.chromium.base.test.util.Feature;
|
||||||
import org.chromium.base.test.util.Features.EnableFeatures;
|
import org.chromium.base.test.util.Features.EnableFeatures;
|
||||||
|
import org.chromium.base.test.util.UrlUtils;
|
||||||
import org.chromium.blink_public.common.BlinkFeatures;
|
import org.chromium.blink_public.common.BlinkFeatures;
|
||||||
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
||||||
import org.chromium.chrome.browser.flags.ChromeSwitches;
|
import org.chromium.chrome.browser.flags.ChromeSwitches;
|
||||||
|
import org.chromium.chrome.browser.fullscreen.BrowserControlsManager;
|
||||||
|
import org.chromium.chrome.browser.fullscreen.FullscreenManagerTestUtils;
|
||||||
import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
|
import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
|
||||||
|
import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
|
||||||
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||||
import org.chromium.chrome.test.util.ChromeRenderTestRule;
|
import org.chromium.chrome.test.util.ChromeRenderTestRule;
|
||||||
import org.chromium.chrome.test.util.NewTabPageTestUtils;
|
import org.chromium.chrome.test.util.NewTabPageTestUtils;
|
||||||
import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
|
import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
|
||||||
import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
|
import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
|
||||||
import org.chromium.components.embedder_support.util.UrlConstants;
|
import org.chromium.components.embedder_support.util.UrlConstants;
|
||||||
|
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||||
import org.chromium.content_public.browser.test.util.UiUtils;
|
import org.chromium.content_public.browser.test.util.UiUtils;
|
||||||
import org.chromium.content_public.browser.test.util.WebContentsUtils;
|
import org.chromium.content_public.browser.test.util.WebContentsUtils;
|
||||||
import org.chromium.net.test.EmbeddedTestServer;
|
import org.chromium.net.test.EmbeddedTestServer;
|
||||||
@@ -70,6 +77,15 @@ public class ScreenshotCaptureTest {
|
|||||||
|
|
||||||
private static final String TEST_PAGE = "/chrome/test/data/android/simple.html";
|
private static final String TEST_PAGE = "/chrome/test/data/android/simple.html";
|
||||||
private static final String TEST_PAGE_2 = "/chrome/test/data/android/google.html";
|
private static final String TEST_PAGE_2 = "/chrome/test/data/android/google.html";
|
||||||
|
private static final String LONG_HTML_TEST_PAGE =
|
||||||
|
UrlUtils.encodeHtmlDataUri(
|
||||||
|
"<html>"
|
||||||
|
+ "<head>"
|
||||||
|
+ " <meta name=\"viewport\" content=\"width=device-width\">"
|
||||||
|
+ "</head>"
|
||||||
|
+ "<body style='height:100000px;'>"
|
||||||
|
+ "</body>"
|
||||||
|
+ "</html>");
|
||||||
|
|
||||||
private EmbeddedTestServer mTestServer;
|
private EmbeddedTestServer mTestServer;
|
||||||
private Bitmap mCapturedBitmap;
|
private Bitmap mCapturedBitmap;
|
||||||
@@ -93,9 +109,10 @@ public class ScreenshotCaptureTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
// Fix the port cause the screenshot includes the url bar
|
||||||
mTestServer =
|
mTestServer =
|
||||||
EmbeddedTestServer.createAndStartServer(
|
EmbeddedTestServer.createAndStartServerWithPort(
|
||||||
ApplicationProvider.getApplicationContext());
|
ApplicationProvider.getApplicationContext(), 46985);
|
||||||
|
|
||||||
var mSiteSuggestions = NewTabPageTestUtils.createFakeSiteSuggestions(mTestServer);
|
var mSiteSuggestions = NewTabPageTestUtils.createFakeSiteSuggestions(mTestServer);
|
||||||
var mMostVisitedSites = new FakeMostVisitedSites();
|
var mMostVisitedSites = new FakeMostVisitedSites();
|
||||||
@@ -189,6 +206,91 @@ public class ScreenshotCaptureTest {
|
|||||||
mRenderTestRule.compareForResult(mCapturedBitmap, "navigate_away_from_ntp_to_webui_page");
|
mRenderTestRule.compareForResult(mCapturedBitmap, "navigate_away_from_ntp_to_webui_page");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
@Feature({"RenderTest"})
|
||||||
|
// The test is based on 3-button mode. The newer version defaults to gesture mode.
|
||||||
|
@DisableIf.Build(sdk_is_greater_than = VERSION_CODES.S_V2)
|
||||||
|
@ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
|
||||||
|
public void testNavigatingBackToNtpFromNormalPage(boolean nightModeEnabled)
|
||||||
|
throws IOException, TimeoutException, InterruptedException {
|
||||||
|
mActivityTestRule.startMainActivityWithURL(UrlConstants.NTP_URL);
|
||||||
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
|
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
|
||||||
|
|
||||||
|
mActivityTestRule.loadUrl(mTestServer.getURL(TEST_PAGE));
|
||||||
|
|
||||||
|
GestureNavigationUtils mNavUtils = new GestureNavigationUtils(mActivityTestRule);
|
||||||
|
mNavUtils.swipeFromEdgeAndHold(/* leftEdge= */ true);
|
||||||
|
|
||||||
|
CallbackHelper callbackHelper = new CallbackHelper();
|
||||||
|
mActivityTestRule
|
||||||
|
.getWebContents()
|
||||||
|
.captureContentAsBitmapForTesting(
|
||||||
|
bitmap -> {
|
||||||
|
try {
|
||||||
|
mRenderTestRule.compareForResult(
|
||||||
|
bitmap, "navigate_back_to_ntp_from_normal_page");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
callbackHelper.notifyCalled();
|
||||||
|
});
|
||||||
|
callbackHelper.waitForOnly();
|
||||||
|
TestThreadUtils.runOnUiThreadBlocking(() -> mNavUtils.getNavigationHandler().release(true));
|
||||||
|
// Wait animation to be finished. Reduce flakiness caused by being destroyed during a
|
||||||
|
// running animation.
|
||||||
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@MediumTest
|
||||||
|
@Feature({"RenderTest"})
|
||||||
|
// The test is based on 3-button mode. The newer version defaults to gesture mode.
|
||||||
|
@DisableIf.Build(sdk_is_greater_than = VERSION_CODES.S_V2)
|
||||||
|
@ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
|
||||||
|
public void testNavigatingBackToNtpFromNormalPageWithoutTopControls(boolean nightModeEnabled)
|
||||||
|
throws Throwable {
|
||||||
|
TestThreadUtils.runOnUiThreadBlocking(
|
||||||
|
TabStateBrowserControlsVisibilityDelegate::disablePageLoadDelayForTests);
|
||||||
|
mActivityTestRule.startMainActivityWithURL(UrlConstants.NTP_URL);
|
||||||
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
|
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
|
||||||
|
FullscreenManagerTestUtils.disableBrowserOverrides();
|
||||||
|
mActivityTestRule.loadUrl(LONG_HTML_TEST_PAGE);
|
||||||
|
BrowserControlsManager browserControlManager =
|
||||||
|
mActivityTestRule.getActivity().getBrowserControlsManager();
|
||||||
|
int browserControlsHeight = browserControlManager.getTopControlsHeight();
|
||||||
|
FullscreenManagerTestUtils.waitForBrowserControlsToBeMoveable(
|
||||||
|
mActivityTestRule, mActivityTestRule.getActivity().getActivityTab());
|
||||||
|
FullscreenManagerTestUtils.scrollBrowserControls(mActivityTestRule, false);
|
||||||
|
|
||||||
|
FullscreenManagerTestUtils.waitForBrowserControlsPosition(
|
||||||
|
mActivityTestRule, -browserControlsHeight);
|
||||||
|
GestureNavigationUtils mNavUtils = new GestureNavigationUtils(mActivityTestRule);
|
||||||
|
mNavUtils.swipeFromEdgeAndHold(/* leftEdge= */ true);
|
||||||
|
|
||||||
|
CallbackHelper callbackHelper = new CallbackHelper();
|
||||||
|
mActivityTestRule
|
||||||
|
.getWebContents()
|
||||||
|
.captureContentAsBitmapForTesting(
|
||||||
|
bitmap -> {
|
||||||
|
try {
|
||||||
|
mRenderTestRule.compareForResult(
|
||||||
|
bitmap,
|
||||||
|
"navigate_back_to_ntp_from_normal_page_without_top_controls");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
callbackHelper.notifyCalled();
|
||||||
|
});
|
||||||
|
callbackHelper.waitForOnly();
|
||||||
|
TestThreadUtils.runOnUiThreadBlocking(() -> mNavUtils.getNavigationHandler().release(true));
|
||||||
|
// Wait animation to be finished. Reduce flakiness caused by being destroyed during a
|
||||||
|
// running animation.
|
||||||
|
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@MediumTest
|
@MediumTest
|
||||||
public void testNotCaptureSadTab() throws TimeoutException, InterruptedException {
|
public void testNotCaptureSadTab() throws TimeoutException, InterruptedException {
|
||||||
|
@@ -15,6 +15,7 @@ android_library("java") {
|
|||||||
"//base:base_java",
|
"//base:base_java",
|
||||||
"//chrome/browser/flags:java",
|
"//chrome/browser/flags:java",
|
||||||
"//chrome/browser/tab:java",
|
"//chrome/browser/tab:java",
|
||||||
|
"//chrome/browser/ui/android/native_page:java",
|
||||||
"//third_party/androidx:androidx_annotation_annotation_java",
|
"//third_party/androidx:androidx_annotation_annotation_java",
|
||||||
"//third_party/jni_zero:jni_zero_java",
|
"//third_party/jni_zero:jni_zero_java",
|
||||||
"//ui/android:ui_no_recycler_view_java",
|
"//ui/android:ui_no_recycler_view_java",
|
||||||
|
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.gesturenav;
|
|||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -18,7 +17,7 @@ import org.chromium.base.task.PostTask;
|
|||||||
import org.chromium.base.task.TaskTraits;
|
import org.chromium.base.task.TaskTraits;
|
||||||
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
||||||
import org.chromium.chrome.browser.tab.Tab;
|
import org.chromium.chrome.browser.tab.Tab;
|
||||||
import org.chromium.ui.resources.dynamics.CaptureObserver;
|
import org.chromium.ui.resources.dynamics.CaptureUtils;
|
||||||
import org.chromium.ui.resources.dynamics.SoftwareDraw;
|
import org.chromium.ui.resources.dynamics.SoftwareDraw;
|
||||||
|
|
||||||
/** Capture native page as a bitmap. */
|
/** Capture native page as a bitmap. */
|
||||||
@@ -37,10 +36,11 @@ public class NativePageBitmapCapturer implements UnownedUserData {
|
|||||||
* @param tab The target tab to be captured.
|
* @param tab The target tab to be captured.
|
||||||
* @param callback Executed with a non-null bitmap if the tab is presenting a native page. Empty
|
* @param callback Executed with a non-null bitmap if the tab is presenting a native page. Empty
|
||||||
* bitmap if capturing fails, such as out of memory error.
|
* bitmap if capturing fails, such as out of memory error.
|
||||||
|
* @param topControlsHeight Height of the top controls.
|
||||||
* @return True if the capture is successfully triggered; otherwise false.
|
* @return True if the capture is successfully triggered; otherwise false.
|
||||||
*/
|
*/
|
||||||
public static boolean maybeCaptureNativeView(
|
public static boolean maybeCaptureNativeView(
|
||||||
@NonNull Tab tab, @NonNull Callback<Bitmap> callback) {
|
@NonNull Tab tab, @NonNull Callback<Bitmap> callback, int topControlsHeight) {
|
||||||
if (!tab.isNativePage()) {
|
if (!tab.isNativePage()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -53,25 +53,19 @@ public class NativePageBitmapCapturer implements UnownedUserData {
|
|||||||
final var capturer = CAPTURER_KEY.retrieveDataFromHost(host);
|
final var capturer = CAPTURER_KEY.retrieveDataFromHost(host);
|
||||||
|
|
||||||
View view = tab.getView();
|
View view = tab.getView();
|
||||||
Rect viewBound = new Rect(0, 0, view.getWidth(), view.getHeight());
|
|
||||||
|
Bitmap bitmap = CaptureUtils.createBitmap(view.getWidth(), view.getHeight());
|
||||||
|
bitmap.eraseColor(tab.getNativePage().getBackgroundColor());
|
||||||
|
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
float scale = capturer.getScale();
|
||||||
|
|
||||||
// TODO(crbug.com/330230340): capture bitmap asynchronously.
|
// TODO(crbug.com/330230340): capture bitmap asynchronously.
|
||||||
capturer.mSoftwareDraw.startBitmapCapture(
|
// Translate to exclude the area of the top controls.
|
||||||
view,
|
canvas.translate(0, -topControlsHeight);
|
||||||
viewBound,
|
canvas.scale(scale, scale);
|
||||||
capturer.getScale(),
|
view.draw(canvas);
|
||||||
new CaptureObserver() {
|
PostTask.postTask(TaskTraits.UI_USER_VISIBLE, () -> callback.onResult(bitmap));
|
||||||
@Override
|
|
||||||
public void onCaptureStart(Canvas canvas, Rect dirtyRect) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCaptureEnd() {}
|
|
||||||
},
|
|
||||||
(bitmap) -> {
|
|
||||||
// The screenshot callback must be dispatched asynchronously. See
|
|
||||||
// WebContentsDelegateAndroid#maybeCopyContentAreaAsBitmap.
|
|
||||||
PostTask.postTask(TaskTraits.UI_USER_VISIBLE, () -> callback.onResult(bitmap));
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,8 @@ import org.chromium.base.test.util.CommandLineFlags;
|
|||||||
import org.chromium.base.test.util.Features;
|
import org.chromium.base.test.util.Features;
|
||||||
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
||||||
import org.chromium.chrome.browser.flags.ChromeSwitches;
|
import org.chromium.chrome.browser.flags.ChromeSwitches;
|
||||||
|
import org.chromium.chrome.browser.tab.TabTestUtils;
|
||||||
|
import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
|
||||||
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
||||||
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||||
import org.chromium.components.embedder_support.util.UrlConstants;
|
import org.chromium.components.embedder_support.util.UrlConstants;
|
||||||
@@ -39,6 +41,12 @@ public class NativePageBitmapCapturerTest {
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
public void testWithNativePage() throws TimeoutException {
|
public void testWithNativePage() throws TimeoutException {
|
||||||
mTabbedActivityTestRule.startMainActivityWithURL(UrlConstants.NTP_URL);
|
mTabbedActivityTestRule.startMainActivityWithURL(UrlConstants.NTP_URL);
|
||||||
|
|
||||||
|
final TabWebContentsDelegateAndroid delegate =
|
||||||
|
TabTestUtils.getTabWebContentsDelegate(
|
||||||
|
mTabbedActivityTestRule.getActivity().getActivityTab());
|
||||||
|
final int topControlsHeight = delegate.getTopControlsHeight();
|
||||||
|
|
||||||
CallbackHelper callbackHelper = new CallbackHelper();
|
CallbackHelper callbackHelper = new CallbackHelper();
|
||||||
TestThreadUtils.runOnUiThreadBlocking(
|
TestThreadUtils.runOnUiThreadBlocking(
|
||||||
() -> {
|
() -> {
|
||||||
@@ -47,7 +55,8 @@ public class NativePageBitmapCapturerTest {
|
|||||||
mTabbedActivityTestRule.getActivity().getActivityTab(),
|
mTabbedActivityTestRule.getActivity().getActivityTab(),
|
||||||
(bitmap) -> {
|
(bitmap) -> {
|
||||||
callbackHelper.notifyCalled();
|
callbackHelper.notifyCalled();
|
||||||
}));
|
},
|
||||||
|
topControlsHeight));
|
||||||
});
|
});
|
||||||
|
|
||||||
callbackHelper.waitForOnly();
|
callbackHelper.waitForOnly();
|
||||||
@@ -57,6 +66,12 @@ public class NativePageBitmapCapturerTest {
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
public void testWithNonNativePage() {
|
public void testWithNonNativePage() {
|
||||||
mTabbedActivityTestRule.startMainActivityOnBlankPage();
|
mTabbedActivityTestRule.startMainActivityOnBlankPage();
|
||||||
|
|
||||||
|
final TabWebContentsDelegateAndroid delegate =
|
||||||
|
TabTestUtils.getTabWebContentsDelegate(
|
||||||
|
mTabbedActivityTestRule.getActivity().getActivityTab());
|
||||||
|
final int topControlsHeight = delegate.getTopControlsHeight();
|
||||||
|
|
||||||
CallbackHelper callbackHelper = new CallbackHelper();
|
CallbackHelper callbackHelper = new CallbackHelper();
|
||||||
TestThreadUtils.runOnUiThreadBlocking(
|
TestThreadUtils.runOnUiThreadBlocking(
|
||||||
() -> {
|
() -> {
|
||||||
@@ -65,7 +80,8 @@ public class NativePageBitmapCapturerTest {
|
|||||||
mTabbedActivityTestRule.getActivity().getActivityTab(),
|
mTabbedActivityTestRule.getActivity().getActivityTab(),
|
||||||
(bitmap) -> {
|
(bitmap) -> {
|
||||||
callbackHelper.notifyCalled();
|
callbackHelper.notifyCalled();
|
||||||
}));
|
},
|
||||||
|
topControlsHeight));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Capture will be finished before the following task.
|
// Capture will be finished before the following task.
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "base/android/jni_android.h"
|
#include "base/android/jni_android.h"
|
||||||
#include "base/android/jni_array.h"
|
#include "base/android/jni_array.h"
|
||||||
#include "base/android/jni_string.h"
|
#include "base/android/jni_string.h"
|
||||||
|
#include "base/check.h"
|
||||||
#include "base/functional/bind.h"
|
#include "base/functional/bind.h"
|
||||||
#include "base/functional/callback_helpers.h"
|
#include "base/functional/callback_helpers.h"
|
||||||
#include "base/json/json_writer.h"
|
#include "base/json/json_writer.h"
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
#include "ui/gfx/android/java_bitmap.h"
|
#include "ui/gfx/android/java_bitmap.h"
|
||||||
#include "ui/gfx/geometry/point.h"
|
#include "ui/gfx/geometry/point.h"
|
||||||
#include "ui/gfx/geometry/rect.h"
|
#include "ui/gfx/geometry/rect.h"
|
||||||
|
#include "ui/snapshot/snapshot.h"
|
||||||
#include "url/android/gurl_android.h"
|
#include "url/android/gurl_android.h"
|
||||||
#include "url/gurl.h"
|
#include "url/gurl.h"
|
||||||
|
|
||||||
@@ -256,6 +258,28 @@ WebContentsAndroid::GetJavaObject() {
|
|||||||
return base::android::ScopedJavaLocalRef<jobject>(obj_);
|
return base::android::ScopedJavaLocalRef<jobject>(obj_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContentsAndroid::CaptureContentAsBitmapForTesting(
|
||||||
|
JNIEnv* env,
|
||||||
|
const base::android::JavaParamRef<jobject>& jcallback) {
|
||||||
|
ui::GrabViewSnapshot(
|
||||||
|
web_contents_->GetNativeView(), gfx::Rect(web_contents_->GetSize()),
|
||||||
|
base::BindOnce(
|
||||||
|
&WebContentsAndroid::OnFinishGetContentBitmapForTesting,
|
||||||
|
weak_factory_.GetWeakPtr(),
|
||||||
|
base::android::ScopedJavaGlobalRef<jobject>(env, jcallback)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebContentsAndroid::OnFinishGetContentBitmapForTesting(
|
||||||
|
const base::android::JavaRef<jobject>& callback,
|
||||||
|
gfx::Image snapshot) {
|
||||||
|
const SkBitmap bitmap = snapshot.AsBitmap();
|
||||||
|
CHECK(!bitmap.isNull());
|
||||||
|
CHECK(!bitmap.empty());
|
||||||
|
base::android::RunObjectCallbackAndroid(
|
||||||
|
callback,
|
||||||
|
gfx::ConvertToJavaBitmap(bitmap, gfx::OomBehavior::kReturnNullOnOom));
|
||||||
|
}
|
||||||
|
|
||||||
void WebContentsAndroid::ClearNativeReference(JNIEnv* env) {
|
void WebContentsAndroid::ClearNativeReference(JNIEnv* env) {
|
||||||
return web_contents_->ClearWebContentsAndroid();
|
return web_contents_->ClearWebContentsAndroid();
|
||||||
}
|
}
|
||||||
|
@@ -235,6 +235,13 @@ class CONTENT_EXPORT WebContentsAndroid {
|
|||||||
void OnContentForNavigationEntryShown(JNIEnv* env);
|
void OnContentForNavigationEntryShown(JNIEnv* env);
|
||||||
jint GetCurrentBackForwardTransitionStage(JNIEnv* env);
|
jint GetCurrentBackForwardTransitionStage(JNIEnv* env);
|
||||||
|
|
||||||
|
void CaptureContentAsBitmapForTesting(
|
||||||
|
JNIEnv* env,
|
||||||
|
const base::android::JavaParamRef<jobject>& jcallback);
|
||||||
|
void OnFinishGetContentBitmapForTesting(
|
||||||
|
const base::android::JavaRef<jobject>& callback,
|
||||||
|
gfx::Image snapshot);
|
||||||
|
|
||||||
// Adds a crash report, like DumpWithoutCrashing(), including the Java stack
|
// Adds a crash report, like DumpWithoutCrashing(), including the Java stack
|
||||||
// trace from which `web_contents` was created. This is meant to help debug
|
// trace from which `web_contents` was created. This is meant to help debug
|
||||||
// cases where BrowserContext is destroyed before its WebContents.
|
// cases where BrowserContext is destroyed before its WebContents.
|
||||||
|
@@ -25,6 +25,7 @@ import org.jni_zero.CalledByNative;
|
|||||||
import org.jni_zero.JNINamespace;
|
import org.jni_zero.JNINamespace;
|
||||||
import org.jni_zero.NativeMethods;
|
import org.jni_zero.NativeMethods;
|
||||||
|
|
||||||
|
import org.chromium.base.Callback;
|
||||||
import org.chromium.base.JavaExceptionReporter;
|
import org.chromium.base.JavaExceptionReporter;
|
||||||
import org.chromium.base.Log;
|
import org.chromium.base.Log;
|
||||||
import org.chromium.base.ObserverList;
|
import org.chromium.base.ObserverList;
|
||||||
@@ -1248,9 +1249,16 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi
|
|||||||
"Native WebContents already destroyed", mNativeDestroyThrowable);
|
"Native WebContents already destroyed", mNativeDestroyThrowable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void captureContentAsBitmapForTesting(Callback<Bitmap> callback) {
|
||||||
|
WebContentsImplJni.get()
|
||||||
|
.captureContentAsBitmapForTesting(mNativeWebContentsAndroid, callback);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||||
@NativeMethods
|
@NativeMethods
|
||||||
public interface Natives {
|
public interface Natives {
|
||||||
|
|
||||||
// This is static to avoid exposing a public destroy method on the native side of this
|
// This is static to avoid exposing a public destroy method on the native side of this
|
||||||
// class.
|
// class.
|
||||||
void destroyWebContents(long webContentsAndroidPtr);
|
void destroyWebContents(long webContentsAndroidPtr);
|
||||||
@@ -1454,5 +1462,8 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi
|
|||||||
long nativeWebContentsAndroid,
|
long nativeWebContentsAndroid,
|
||||||
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
||||||
BrowserControlsOffsetTagsInfo offsetTagsInfo);
|
BrowserControlsOffsetTagsInfo offsetTagsInfo);
|
||||||
|
|
||||||
|
void captureContentAsBitmapForTesting(
|
||||||
|
long nativeWebContentsAndroid, Callback<Bitmap> callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package org.chromium.content_public.browser;
|
package org.chromium.content_public.browser;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
@@ -11,6 +12,7 @@ import android.os.Parcelable;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.chromium.base.Callback;
|
||||||
import org.chromium.blink_public.input.SelectionGranularity;
|
import org.chromium.blink_public.input.SelectionGranularity;
|
||||||
import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
|
import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
|
||||||
import org.chromium.content_public.browser.back_forward_transition.AnimationStage;
|
import org.chromium.content_public.browser.back_forward_transition.AnimationStage;
|
||||||
@@ -621,4 +623,6 @@ public interface WebContents extends Parcelable {
|
|||||||
void notifyControlsConstraintsChanged(
|
void notifyControlsConstraintsChanged(
|
||||||
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
||||||
BrowserControlsOffsetTagsInfo offsetTagsInfo);
|
BrowserControlsOffsetTagsInfo offsetTagsInfo);
|
||||||
|
|
||||||
|
void captureContentAsBitmapForTesting(Callback<Bitmap> callback);
|
||||||
}
|
}
|
||||||
|
@@ -5,12 +5,14 @@
|
|||||||
package org.chromium.content_public.browser.test.mock;
|
package org.chromium.content_public.browser.test.mock;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.chromium.base.Callback;
|
||||||
import org.chromium.blink_public.input.SelectionGranularity;
|
import org.chromium.blink_public.input.SelectionGranularity;
|
||||||
import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
|
import org.chromium.cc.input.BrowserControlsOffsetTagsInfo;
|
||||||
import org.chromium.content_public.browser.GlobalRenderFrameHostId;
|
import org.chromium.content_public.browser.GlobalRenderFrameHostId;
|
||||||
@@ -375,6 +377,9 @@ public class MockWebContents implements WebContents {
|
|||||||
return AnimationStage.NONE;
|
return AnimationStage.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void captureContentAsBitmapForTesting(Callback<Bitmap> callback) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyControlsConstraintsChanged(
|
public void notifyControlsConstraintsChanged(
|
||||||
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
BrowserControlsOffsetTagsInfo oldOffsetTagsInfo,
|
||||||
|
Reference in New Issue
Block a user