Commit 31f4a641 authored by Wei-Yin Chen (陳威尹)'s avatar Wei-Yin Chen (陳威尹) Committed by Commit Bot

Show on-disk thumbnail before live content is captured

This is a follow up for https://crrev.com/c/1525627.

Before this CL, the thumbnail of the current tab is requested,
and is shown in Grid Tab Switcher when captured. However, the latency
of this pipeline is a bit long, and this leads to a visible flash
if the thumbnail has been cleared when recycled, which is done in
https://crrev.com/c/1595128.

This CL shows the on-disk thumbnail first, and updates that with
the newly requested screenshot of the live content if available.

Bug: 959054
Change-Id: I15a44d8a6e7bef4f71ae429b4ec1136697e53246
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1612230Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Commit-Queue: Wei-Yin Chen (陳威尹) <wychen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661156}
parent 8b4baa14
......@@ -28,6 +28,7 @@ import org.chromium.content_public.browser.UiThreadTaskTraits;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* A {@link TabListMediator.ThumbnailProvider} that will create a single Bitmap Thumbnail for all
......@@ -106,18 +107,22 @@ public class MultiThumbnailCardProvider implements TabListMediator.ThumbnailProv
final int index = i;
final String url = mTabs.get(i).getUrl();
final boolean isIncognito = mTabs.get(i).isIncognito();
// getTabThumbnailWithCallback() might call the callback up to twice,
// so use |lastFavicon| to avoid fetching the favicon the second time.
// Fetching the favicon after getting the live thumbnail would lead to
// visible flicker.
final AtomicReference<Drawable> lastFavicon = new AtomicReference<>();
mTabContentManager.getTabThumbnailWithCallback(mTabs.get(i), thumbnail -> {
drawThumbnailBitmapOnCanvasWithFrame(thumbnail, index);
mTabListFaviconProvider.getFaviconForUrlAsync(
url, isIncognito, (Drawable favicon) -> {
drawFaviconDrawableOnCanvasWithFrame(favicon, index);
if (mThumbnailsToFetch.decrementAndGet() == 0) {
PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE,
()
-> mFinalCallback.onResult(
mMultiThumbnailBitmap));
}
});
if (lastFavicon.get() != null) {
drawFaviconThenMaybeSendBack(lastFavicon.get(), index);
} else {
mTabListFaviconProvider.getFaviconForUrlAsync(
url, isIncognito, (Drawable favicon) -> {
lastFavicon.set(favicon);
drawFaviconThenMaybeSendBack(favicon, index);
});
}
}, mForceUpdate && i == 0);
} else {
drawThumbnailBitmapOnCanvasWithFrame(null, i);
......@@ -164,6 +169,14 @@ public class MultiThumbnailCardProvider implements TabListMediator.ThumbnailProv
favicon.draw(mCanvas);
}
private void drawFaviconThenMaybeSendBack(Drawable favicon, int index) {
drawFaviconDrawableOnCanvasWithFrame(favicon, index);
if (mThumbnailsToFetch.decrementAndGet() == 0) {
PostTask.postTask(UiThreadTaskTraits.USER_VISIBLE,
() -> mFinalCallback.onResult(mMultiThumbnailBitmap));
}
}
private void fetch() {
initializeAndStartFetching(mInitialTab);
}
......
......@@ -256,24 +256,28 @@ public class TabContentManager {
* TODO(yusufo): Change the plumbing so that at the least a {@link android.net.Uri} is sent
* over JNI of an uncompressed file on disk.
* @param tab The tab to get the thumbnail for.
* @param callback The callback to send the {@link Bitmap} with.
* @param callback The callback to send the {@link Bitmap} with. Can be called up to twice when
* forceUpdate; otherwise always called exactly once.
* @param forceUpdate Whether to obtain the thumbnail from the live content.
*/
public void getTabThumbnailWithCallback(
Tab tab, Callback<Bitmap> callback, boolean forceUpdate) {
if (mNativeTabContentManager == 0 || !mSnapshotsEnabled) return;
// Reading thumbnail from disk is faster than taking screenshot from live Tab, so fetch
// that first even if |forceUpdate|.
nativeGetTabThumbnailWithCallback(mNativeTabContentManager, tab.getId(), callback);
if (forceUpdate) {
cacheTabThumbnail(tab, (bitmap) -> {
// Null check to avoid having a Bitmap from nativeGetTabThumbnailWithCallback() but
// cleared here.
// If invalidation is not needed, cacheTabThumbnail() might not do anything and
// send back null.
if (bitmap != null) {
callback.onResult(bitmap);
return;
}
// If invalidation is not needed, cacheTabThumbnail() might not do anything, so we
// need to fall back to reading from disk.
nativeGetTabThumbnailWithCallback(mNativeTabContentManager, tab.getId(), callback);
});
} else {
nativeGetTabThumbnailWithCallback(mNativeTabContentManager, tab.getId(), callback);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment