Index: chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java |
deleted file mode 100644 |
index f85cccf2bc0b9ba40ccf1087a3632276c74c702b..0000000000000000000000000000000000000000 |
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java |
+++ /dev/null |
@@ -1,334 +0,0 @@ |
-// Copyright 2015 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.tab; |
- |
-import android.content.res.Resources; |
-import android.graphics.Bitmap; |
-import android.graphics.Bitmap.Config; |
-import android.graphics.Canvas; |
-import android.graphics.Paint; |
-import android.graphics.Rect; |
-import android.os.Handler; |
-import android.text.TextUtils; |
-import android.util.Log; |
- |
-import org.chromium.chrome.R; |
-import org.chromium.chrome.browser.ChromeActivity; |
-import org.chromium.chrome.browser.EmptyTabObserver; |
-import org.chromium.chrome.browser.Tab; |
-import org.chromium.chrome.browser.TabObserver; |
-import org.chromium.chrome.browser.UrlConstants; |
-import org.chromium.chrome.browser.profiles.Profile; |
-import org.chromium.chrome.browser.util.MathUtils; |
-import org.chromium.content.browser.ContentReadbackHandler; |
-import org.chromium.content.browser.ContentViewCore; |
-import org.chromium.content_public.browser.GestureStateListener; |
-import org.chromium.content_public.browser.WebContents; |
-import org.chromium.ui.base.WindowAndroid; |
- |
-/** |
- * Handles capturing most visited thumbnails for a tab. |
- */ |
-public class ThumbnailTabHelper { |
- |
- private static final String TAG = "ThumbnailTabHelper"; |
- |
- /** The general motivation for this value is giving the scrollbar fadeout |
- * animation sufficient time to finish before the capture executes. */ |
- private static final int THUMBNAIL_CAPTURE_DELAY_MS = 350; |
- |
- private final Tab mTab; |
- private final Handler mHandler; |
- |
- private final int mThumbnailWidth; |
- private final int mThumbnailHeight; |
- |
- private ContentViewCore mContentViewCore; |
- private boolean mThumbnailCapturedForLoad; |
- private boolean mIsRenderViewHostReady; |
- private boolean mWasRenderViewHostReady; |
- |
- private final Runnable mThumbnailRunnable = new Runnable() { |
- @Override |
- public void run() { |
- // http://crbug.com/461506 : Do not get thumbnail unless render view host is ready. |
- if (!mIsRenderViewHostReady) return; |
- |
- if (mThumbnailCapturedForLoad) return; |
- // Prevent redundant thumbnail capture attempts. |
- mThumbnailCapturedForLoad = true; |
- if (!canUpdateHistoryThumbnail()) { |
- // Allow a hidden tab to re-attempt capture in the future via |show()|. |
- mThumbnailCapturedForLoad = !mTab.isHidden(); |
- return; |
- } |
- if (!shouldUpdateThumbnail()) return; |
- |
- // Scale the image so we're not copying more than we need to (from |
- // the GPU). |
- int[] dim = new int[] { |
- mTab.getWidth(), mTab.getHeight() |
- }; |
- MathUtils.scaleToFitTargetSize(dim, mThumbnailWidth, mThumbnailHeight); |
- |
- ContentReadbackHandler readbackHandler = getActivity().getContentReadbackHandler(); |
- if (readbackHandler == null || mTab.getContentViewCore() == null) return; |
- final String requestedUrl = mTab.getUrl(); |
- ContentReadbackHandler.GetBitmapCallback bitmapCallback = |
- new ContentReadbackHandler.GetBitmapCallback() { |
- @Override |
- public void onFinishGetBitmap(Bitmap bitmap, int response) { |
- // Ensure that the URLs match for the requested page, and ensure |
- // that the page is still valid for thumbnail capturing (i.e. |
- // not showing an error page). |
- if (bitmap == null |
- || !TextUtils.equals(requestedUrl, mTab.getUrl()) |
- || !mThumbnailCapturedForLoad |
- || !canUpdateHistoryThumbnail()) { |
- return; |
- } |
- updateHistoryThumbnail(bitmap); |
- bitmap.recycle(); |
- } |
- }; |
- readbackHandler.getContentBitmapAsync(1, new Rect(0, 0, dim[0], dim[1]), |
- mTab.getContentViewCore(), Bitmap.Config.ARGB_8888, bitmapCallback); |
- } |
- }; |
- |
- private final TabObserver mTabObserver = new EmptyTabObserver() { |
- @Override |
- public void onContentChanged(Tab tab) { |
- ThumbnailTabHelper.this.onContentChanged(); |
- } |
- |
- @Override |
- public void onCrash(Tab tab, boolean sadTabShown) { |
- cancelThumbnailCapture(); |
- } |
- |
- @Override |
- public void onPageLoadStarted(Tab tab, String url) { |
- cancelThumbnailCapture(); |
- mThumbnailCapturedForLoad = false; |
- } |
- |
- @Override |
- public void onPageLoadFinished(Tab tab) { |
- rescheduleThumbnailCapture(); |
- } |
- |
- @Override |
- public void onPageLoadFailed(Tab tab, int errorCode) { |
- cancelThumbnailCapture(); |
- } |
- |
- @Override |
- public void onShown(Tab tab) { |
- // For tabs opened in the background, they may finish loading prior to becoming visible |
- // and the thumbnail capture triggered as part of load finish will be skipped as the |
- // tab has nothing rendered. To handle this case, we also attempt thumbnail capture |
- // when showing the tab to give it a better chance to have valid content. |
- rescheduleThumbnailCapture(); |
- } |
- |
- @Override |
- public void onClosingStateChanged(Tab tab, boolean closing) { |
- if (closing) cancelThumbnailCapture(); |
- } |
- |
- @Override |
- public void onDestroyed(Tab tab) { |
- mTab.removeObserver(mTabObserver); |
- if (mContentViewCore != null) { |
- mContentViewCore.removeGestureStateListener(mGestureListener); |
- mContentViewCore = null; |
- } |
- } |
- |
- @Override |
- public void onDidStartProvisionalLoadForFrame( |
- Tab tab, long frameId, long parentFrameId, boolean isMainFrame, String validatedUrl, |
- boolean isErrorPage, boolean isIframeSrcdoc) { |
- if (isMainFrame) { |
- mWasRenderViewHostReady = mIsRenderViewHostReady; |
- mIsRenderViewHostReady = false; |
- } |
- } |
- |
- @Override |
- public void onDidFailLoad( |
- Tab tab, boolean isProvisionalLoad, boolean isMainFrame, int errorCode, |
- String description, String failingUrl) { |
- // For a case that URL overriding happens, we should recover |mIsRenderViewHostReady| to |
- // its old value to enable capturing thumbnail of the current page. |
- // If this failure shows an error page, capturing thumbnail will be denied anyway in |
- // canUpdateHistoryThumbnail(). |
- if (isProvisionalLoad && isMainFrame) mIsRenderViewHostReady = mWasRenderViewHostReady; |
- } |
- |
- @Override |
- public void onDidCommitProvisionalLoadForFrame( |
- Tab tab, long frameId, boolean isMainFrame, String url, int transitionType) { |
- if (isMainFrame) mIsRenderViewHostReady = true; |
- } |
- }; |
- |
- private GestureStateListener mGestureListener = new GestureStateListener() { |
- @Override |
- public void onFlingStartGesture(int vx, int vy, int scrollOffsetY, int scrollExtentY) { |
- cancelThumbnailCapture(); |
- } |
- |
- @Override |
- public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) { |
- rescheduleThumbnailCapture(); |
- } |
- |
- @Override |
- public void onScrollStarted(int scrollOffsetY, int scrollExtentY) { |
- cancelThumbnailCapture(); |
- } |
- |
- @Override |
- public void onScrollEnded(int scrollOffsetY, int scrollExtentY) { |
- rescheduleThumbnailCapture(); |
- } |
- }; |
- |
- /** |
- * Creates a thumbnail tab helper for the given tab. |
- * @param tab The Tab whose thumbnails will be generated by this helper. |
- */ |
- public static void createForTab(Tab tab) { |
- new ThumbnailTabHelper(tab); |
- } |
- |
- /** |
- * Constructs the thumbnail tab helper for a given Tab. |
- * @param tab The Tab whose thumbnails will be generated by this helper. |
- */ |
- private ThumbnailTabHelper(Tab tab) { |
- mTab = tab; |
- mTab.addObserver(mTabObserver); |
- |
- mHandler = new Handler(); |
- |
- Resources res = tab.getWindowAndroid().getApplicationContext().getResources(); |
- mThumbnailWidth = res.getDimensionPixelSize(R.dimen.most_visited_thumbnail_width); |
- mThumbnailHeight = res.getDimensionPixelSize(R.dimen.most_visited_thumbnail_height); |
- |
- onContentChanged(); |
- } |
- |
- private void onContentChanged() { |
- if (mContentViewCore != null) { |
- mContentViewCore.removeGestureStateListener(mGestureListener); |
- } |
- |
- mContentViewCore = mTab.getContentViewCore(); |
- if (mContentViewCore != null) { |
- mContentViewCore.addGestureStateListener(mGestureListener); |
- nativeInitThumbnailHelper(mContentViewCore.getWebContents()); |
- } |
- } |
- |
- private ChromeActivity getActivity() { |
- WindowAndroid window = mTab.getWindowAndroid(); |
- return (ChromeActivity) window.getActivity().get(); |
- } |
- |
- private void cancelThumbnailCapture() { |
- mHandler.removeCallbacks(mThumbnailRunnable); |
- } |
- |
- private void rescheduleThumbnailCapture() { |
- if (mThumbnailCapturedForLoad) return; |
- cancelThumbnailCapture(); |
- // Capture will be rescheduled when the GestureStateListener receives a |
- // scroll or fling end notification. |
- if (mTab.getContentViewCore() != null |
- && mTab.getContentViewCore().isScrollInProgress()) { |
- return; |
- } |
- mHandler.postDelayed(mThumbnailRunnable, THUMBNAIL_CAPTURE_DELAY_MS); |
- } |
- |
- private boolean shouldUpdateThumbnail() { |
- return nativeShouldUpdateThumbnail(mTab.getProfile(), mTab.getUrl()); |
- } |
- |
- private void updateThumbnail(Bitmap bitmap) { |
- if (mTab.getContentViewCore() != null) { |
- final boolean atTop = mTab.getContentViewCore().computeVerticalScrollOffset() == 0; |
- nativeUpdateThumbnail(mTab.getWebContents(), bitmap, atTop); |
- } |
- } |
- |
- private boolean canUpdateHistoryThumbnail() { |
- String url = mTab.getUrl(); |
- if (url.startsWith(UrlConstants.CHROME_SCHEME) |
- || url.startsWith(UrlConstants.CHROME_NATIVE_SCHEME)) { |
- return false; |
- } |
- return mTab.isReady() |
- && !mTab.isShowingErrorPage() |
- && !mTab.isHidden() |
- && !mTab.isShowingSadTab() |
- && !mTab.isShowingInterstitialPage() |
- && mTab.getProgress() == 100 |
- && mTab.getWidth() > 0 |
- && mTab.getHeight() > 0; |
- } |
- |
- private void updateHistoryThumbnail(Bitmap bitmap) { |
- if (mTab.isIncognito()) return; |
- |
- // TODO(yusufo): It will probably be faster and more efficient on resources to do this on |
- // the native side, but the thumbnail_generator code has to be refactored a bit to allow |
- // creating a downsized version of a bitmap progressively. |
- if (bitmap.getWidth() != mThumbnailWidth |
- || bitmap.getHeight() != mThumbnailHeight |
- || bitmap.getConfig() != Config.ARGB_8888) { |
- try { |
- int[] dim = new int[] { |
- bitmap.getWidth(), bitmap.getHeight() |
- }; |
- // If the thumbnail size is small compared to the bitmap size downsize in |
- // two stages. This makes the final quality better. |
- float scale = Math.max( |
- (float) mThumbnailWidth / dim[0], |
- (float) mThumbnailHeight / dim[1]); |
- int adjustedWidth = (scale < 1) |
- ? mThumbnailWidth * (int) (1 / Math.sqrt(scale)) : mThumbnailWidth; |
- int adjustedHeight = (scale < 1) |
- ? mThumbnailHeight * (int) (1 / Math.sqrt(scale)) : mThumbnailHeight; |
- scale = MathUtils.scaleToFitTargetSize(dim, adjustedWidth, adjustedHeight); |
- // Horizontally center the source bitmap in the final result. |
- float leftOffset = (adjustedWidth - dim[0]) / 2.0f / scale; |
- Bitmap tmpBitmap = Bitmap.createBitmap(adjustedWidth, |
- adjustedHeight, Config.ARGB_8888); |
- Canvas c = new Canvas(tmpBitmap); |
- c.scale(scale, scale); |
- c.drawBitmap(bitmap, leftOffset, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); |
- if (scale < 1) { |
- tmpBitmap = Bitmap.createScaledBitmap(tmpBitmap, |
- mThumbnailWidth, mThumbnailHeight, true); |
- } |
- updateThumbnail(tmpBitmap); |
- tmpBitmap.recycle(); |
- } catch (OutOfMemoryError ex) { |
- Log.w(TAG, "OutOfMemoryError while updating the history thumbnail."); |
- } |
- } else { |
- updateThumbnail(bitmap); |
- } |
- } |
- |
- private static native void nativeInitThumbnailHelper(WebContents webContents); |
- private static native void nativeUpdateThumbnail( |
- WebContents webContents, Bitmap bitmap, boolean atTop); |
- private static native boolean nativeShouldUpdateThumbnail(Profile profile, String url); |
-} |