blob: 5bc3703e4131c5a13f57cce6a863155601e3caf6 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.wallpaper.asset;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.LruCache;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityManagerCompat;
import java.util.Objects;
/**
* Implementation of {@link Asset} that wraps another {@link Asset} but keeps an LRU cache of
* bitmaps generated by {@link #decodeBitmap(int, int, BitmapReceiver)} to avoid having to decode
* the same bitmap multiple times.
* The cache key is the wrapped Asset and the target Width and Height requested, so that we only
* reuse bitmaps of the same size.
*/
public class BitmapCachingAsset extends Asset {
private static class CacheKey {
final Asset asset;
final int width;
final int height;
CacheKey(Asset asset, int width, int height) {
this.asset = asset;
this.width = width;
this.height = height;
}
@Override
public int hashCode() {
return Objects.hash(asset, width, height);
}
@Override
public boolean equals(Object obj) {
return obj instanceof CacheKey
&& ((CacheKey)obj).asset == this.asset
&& ((CacheKey)obj).width == this.width
&& ((CacheKey)obj).height == this.height;
}
}
private static int cacheSize = 100 * 1024 * 1024; // 100MiB
private static LruCache<CacheKey, Bitmap> sCache = new LruCache<CacheKey, Bitmap>(cacheSize) {
@Override protected int sizeOf(CacheKey key, Bitmap value) {
return value.getByteCount();
}
};
private final boolean mIsLowRam;
private final Asset mOriginalAsset;
public BitmapCachingAsset(Context context, Asset originalAsset) {
mOriginalAsset = originalAsset;
mIsLowRam = ActivityManagerCompat.isLowRamDevice(
(ActivityManager) context.getApplicationContext().getSystemService(
Context.ACTIVITY_SERVICE));
}
@Override
public void decodeBitmap(int targetWidth, int targetHeight, BitmapReceiver receiver) {
// Skip the cache in low ram devices
if (mIsLowRam) {
mOriginalAsset.decodeBitmap(targetWidth, targetHeight, receiver::onBitmapDecoded);
return;
}
CacheKey key = new CacheKey(mOriginalAsset, targetWidth, targetHeight);
Bitmap cached = sCache.get(key);
if (cached != null) {
receiver.onBitmapDecoded(cached);
} else {
mOriginalAsset.decodeBitmap(targetWidth, targetHeight, bitmap -> {
if (bitmap != null) {
sCache.put(key, bitmap);
}
receiver.onBitmapDecoded(bitmap);
});
}
}
@Override
public void decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight,
BitmapReceiver receiver) {
mOriginalAsset.decodeBitmapRegion(rect, targetWidth, targetHeight, receiver);
}
@Override
public void decodeRawDimensions(@Nullable Activity activity, DimensionsReceiver receiver) {
mOriginalAsset.decodeRawDimensions(activity, receiver);
}
@Override
public boolean supportsTiling() {
return mOriginalAsset.supportsTiling();
}
}