// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.prerender; import android.app.Application; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.view.WindowManager; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; import org.chromium.chrome.browser.WebContentsFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.content_public.browser.WebContents; /** * A handler class for prerender requests coming from other applications. */ @JNINamespace("prerender") public class ExternalPrerenderHandler { private long mNativeExternalPrerenderHandler; public ExternalPrerenderHandler() { mNativeExternalPrerenderHandler = nativeInit(); } /** * Add a prerender for the given url and given content view dimensions. * <p> * The generated {@link WebContents} does not actually contain the prerendered contents but * must be used as the container that you load the prerendered URL into. * * @param profile The profile to use for the prerender. * @param url The url to prerender. * @param referrer The referrer for the prerender request. * @param bounds The bounds for the content view (render widget host view) for the prerender. * @param prerenderOnCellular Whether the prerender should happen if the device has a cellular * connection. * @return The {@link WebContents} that is linked to this prerender. {@code null} if * unsuccessful. */ public WebContents addPrerender(Profile profile, String url, String referrer, Rect bounds, boolean prerenderOnCellular) { WebContents webContents = WebContentsFactory.createWebContents(false, false); if (addPrerender(profile, webContents, url, referrer, bounds, prerenderOnCellular)) { return webContents; } if (webContents != null) webContents.destroy(); return null; } /** * Adds a prerender for the given URL to an existing {@link WebContents} with the given * dimensions. * * @param profile The profile to use for the prerender. * @param webContents The WebContents to add the prerender to. * @param url The url to prerender. * @param referrer The referrer for the prerender request. * @param bounds The bounds for the content view (render widget host view) for the prerender. * @param prerenderOnCellular Whether the prerender should happen if the device has a cellular * connection. * @return Whether the prerender was successful. */ public boolean addPrerender(Profile profile, WebContents webContents, String url, String referrer, Rect bounds, boolean prerenderOnCellular) { return nativeAddPrerender(mNativeExternalPrerenderHandler, profile, webContents, url, referrer, bounds.top, bounds.left, bounds.bottom, bounds.right, prerenderOnCellular); } /** * Cancel the current prerender action on this {@link ExternalPrerenderHandler}. */ public void cancelCurrentPrerender() { nativeCancelCurrentPrerender(mNativeExternalPrerenderHandler); } /** * Check whether a given url has been prerendering for the given profile and session id for the * given web contents. * @param profile The profile to check for prerendering. * @param url The url to check for prerender. * @param webContents The {@link WebContents} for which to compare the session info. * @return Whether the given url was prerendered. */ @VisibleForTesting public static boolean hasPrerenderedUrl(Profile profile, String url, WebContents webContents) { return nativeHasPrerenderedUrl(profile, url, webContents); } /** * Check whether a given url has been prerendering for the given profile and session id for the * given web contents, and has finished loading. * @param profile The profile to check for prerendering. * @param url The url to check for prerender. * @param webContents The {@link WebContents} for which to compare the session info. * @return Whether the given url was prerendered and has finished loading. */ @VisibleForTesting public static boolean hasPrerenderedAndFinishedLoadingUrl( Profile profile, String url, WebContents webContents) { return nativeHasPrerenderedAndFinishedLoadingUrl(profile, url, webContents); } /** * Provides an estimate of the contents size. * * The estimate is likely to be incorrect. This is not a problem, as the aim * is to avoid getting a different layout and resources than needed at * render time. * @param application The application to use for getting resources. * @param convertToDp Whether the value should be converted to dp from pixels. * @return The estimated prerender size in pixels or dp. */ public static Rect estimateContentSize(Application application, boolean convertToDp) { // The size is estimated as: // X = screenSizeX // Y = screenSizeY - top bar - bottom bar - custom tabs bar // The bounds rectangle includes the bottom bar and the custom tabs bar as well. Rect screenBounds = new Rect(); Point screenSize = new Point(); WindowManager wm = (WindowManager) application.getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getSize(screenSize); Resources resources = application.getResources(); int statusBarId = resources.getIdentifier("status_bar_height", "dimen", "android"); try { screenSize.y -= resources.getDimensionPixelSize(statusBarId); } catch (Resources.NotFoundException e) { // Nothing, this is just a best effort estimate. } screenBounds.set(0, resources.getDimensionPixelSize(R.dimen.custom_tabs_control_container_height), screenSize.x, screenSize.y); if (convertToDp) { float density = resources.getDisplayMetrics().density; screenBounds.top = (int) Math.ceil(screenBounds.top / density); screenBounds.left = (int) Math.ceil(screenBounds.left / density); screenBounds.right = (int) Math.ceil(screenBounds.right / density); screenBounds.bottom = (int) Math.ceil(screenBounds.bottom / density); } return screenBounds; } private static native long nativeInit(); private static native boolean nativeAddPrerender( long nativeExternalPrerenderHandlerAndroid, Profile profile, WebContents webContents, String url, String referrer, int top, int left, int bottom, int right, boolean prerenderOnCellular); private static native boolean nativeHasPrerenderedUrl( Profile profile, String url, WebContents webContents); private static native boolean nativeHasPrerenderedAndFinishedLoadingUrl( Profile profile, String url, WebContents webContents); private static native void nativeCancelCurrentPrerender( long nativeExternalPrerenderHandlerAndroid); }