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

Unregister the ViewResourceAdapter for Grid Tab Switcher after animation

A ViewResourceAdapter is used to show the Grid Tab Switcher (GTS) in the
background when playing the Tab-to-Grid transition animation. After the
animation is done, the Java-side bitmap is released in
https://crrev.com/c/1636833 and https://crrev.com/c/1639150, but the
native-side bitmap is kept, wasting ~3MB of native memory on high-end
phones (assuming downsampling scale = 0.5).

The effects on performance (frame rate, max frame interval, etc) are
within error margin.

Bug: 971281
Change-Id: I9b29a91cb593c46505f1d2be29f7d3dd5e12feb6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1645458
Commit-Queue: Wei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669996}
parent fbde25e7
......@@ -86,7 +86,9 @@ class TabListRecyclerView extends RecyclerView {
private ValueAnimator mFadeInAnimator;
private ValueAnimator mFadeOutAnimator;
private VisibilityListener mListener;
private DynamicResourceLoader mLoader;
private ViewResourceAdapter mDynamicView;
private boolean mIsDynamicViewRegistered;
private long mLastDirtyTime;
private RecyclerView.ItemAnimator mOriginalAnimator;
private ImageView mShadowImageView;
......@@ -111,6 +113,8 @@ class TabListRecyclerView extends RecyclerView {
void prepareOverview() {
endAllAnimations();
registerDynamicView();
// Stop all the animations to make all the items show up and scroll to position immediately.
mOriginalAnimator = getItemAnimator();
setItemAnimator(null);
......@@ -142,8 +146,10 @@ class TabListRecyclerView extends RecyclerView {
// Restore the original value.
setItemAnimator(mOriginalAnimator);
setShadowVisibility(computeVerticalScrollOffset() > 0);
if (mDynamicView != null)
if (mDynamicView != null) {
mDynamicView.dropCachedBitmap();
unregisterDynamicView();
}
}
});
if (!animate) mFadeInAnimator.end();
......@@ -214,7 +220,24 @@ class TabListRecyclerView extends RecyclerView {
}
};
mDynamicView.setDownsamplingScale(getDownsamplingScale());
loader.registerResource(getResourceId(), mDynamicView);
assert mLoader == null : "createDynamicView should only be called once";
mLoader = loader;
}
private void registerDynamicView() {
if (mIsDynamicViewRegistered) return;
if (mLoader == null) return;
mLoader.registerResource(getResourceId(), mDynamicView);
mIsDynamicViewRegistered = true;
}
private void unregisterDynamicView() {
if (!mIsDynamicViewRegistered) return;
if (mLoader == null) return;
mLoader.unregisterResource(getResourceId());
mIsDynamicViewRegistered = false;
}
@SuppressLint("NewApi") // Used on O+, invalidateChildInParent used for previous versions.
......@@ -264,6 +287,9 @@ class TabListRecyclerView extends RecyclerView {
*/
void startHiding(boolean animate) {
endAllAnimations();
registerDynamicView();
mListener.startedHiding(animate);
mFadeOutAnimator = ObjectAnimator.ofFloat(this, View.ALPHA, 0);
mFadeOutAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
......@@ -284,6 +310,7 @@ class TabListRecyclerView extends RecyclerView {
void postHiding() {
if (mDynamicView != null) {
mDynamicView.dropCachedBitmap();
unregisterDynamicView();
}
}
......
......@@ -16,25 +16,25 @@ public abstract class ResourceLoader {
/**
* Called when a resource as finished loading. Note that it is up to the caller to recycle
* any {@link android.graphics.Bitmap}s or clean up any state after making this call.
* @param resType The {@link ResourceType} that loaded the resource.
* @param resType The {@link AndroidResourceType} that loaded the resource.
* @param resId The Android id of the loaded resource.
* @param resource The {@link Resource} of the resource, or {@code null} if one could
* not be loaded.
*/
void onResourceLoaded(int resType, int resId, Resource resource);
void onResourceLoaded(@AndroidResourceType int resType, int resId, Resource resource);
/**
* Called when a resource is unregistered (unneeded). This should only be called for
* dynamic bitmap resources since they change constantly and are replaced with new bitmaps.
* Other resource types should not need this since thay are static for the lifetime of the
* dynamic resources. Dynamic bitmap change constantly and are replaced with new bitmaps.
* Other resource types should not need this since they are static for the lifetime of the
* application.
* @param resType The {@link ResourceType} of resource that was removed.
* @param redId The Android id of the removed resource.
* @param resType The {@link AndroidResourceType} of resource that was removed.
* @param resId The Android id of the removed resource.
*/
void onResourceUnregistered(int resType, int resId);
void onResourceUnregistered(@AndroidResourceType int resType, int resId);
}
private final int mResourceType;
private final @AndroidResourceType int mResourceType;
private final ResourceLoaderCallback mCallback;
/**
......@@ -51,7 +51,7 @@ public abstract class ResourceLoader {
/**
* @return What resource type this {@link ResourceLoader} is responsible for loading.
*/
public int getResourceType() {
public @AndroidResourceType int getResourceType() {
return mResourceType;
}
......
......@@ -122,14 +122,14 @@ public class ResourceManager implements ResourceLoaderCallback {
* @param resId The id of the Android resource.
* @return The corresponding {@link LayoutResource}.
*/
public LayoutResource getResource(int resType, int resId) {
public LayoutResource getResource(@AndroidResourceType int resType, int resId) {
SparseArray<LayoutResource> bucket = mLoadedResources.get(resType);
return bucket != null ? bucket.get(resId) : null;
}
@SuppressWarnings("cast")
@Override
public void onResourceLoaded(int resType, int resId, Resource resource) {
public void onResourceLoaded(@AndroidResourceType int resType, int resId, Resource resource) {
if (resource == null) return;
Bitmap bitmap = resource.getBitmap();
if (bitmap == null) return;
......@@ -144,9 +144,10 @@ public class ResourceManager implements ResourceLoaderCallback {
}
@Override
public void onResourceUnregistered(int resType, int resId) {
// Only remove dynamic bitmaps that were unregistered.
if (resType != AndroidResourceType.DYNAMIC_BITMAP) return;
public void onResourceUnregistered(@AndroidResourceType int resType, int resId) {
// Only remove dynamic resources that were unregistered.
if (resType != AndroidResourceType.DYNAMIC_BITMAP && resType != AndroidResourceType.DYNAMIC)
return;
nativeRemoveResource(mNativeResourceManagerPtr, resType, resId);
}
......@@ -159,7 +160,8 @@ public class ResourceManager implements ResourceLoaderCallback {
nativeClearTintedResourceCache(mNativeResourceManagerPtr);
}
private void saveMetadataForLoadedResource(int resType, int resId, Resource resource) {
private void saveMetadataForLoadedResource(
@AndroidResourceType int resType, int resId, Resource resource) {
SparseArray<LayoutResource> bucket = mLoadedResources.get(resType);
if (bucket == null) {
bucket = new SparseArray<LayoutResource>();
......
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