Use LruCache to cache advanced bluetooth deivce icon
This CL uses LruCache to cache advanced bluetooth device icons. It can reduce the frequency to access content providers to get advanced device icons since the advanced device icons would not changed. Bug: 178255374 Test: make RunSettingsLibRoboTests -j56 Change-Id: I9c8957b5f78ff5047fa4b85fc37a5e27b731465d
This commit is contained in:
@@ -24,6 +24,10 @@ import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothUuid;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -32,12 +36,16 @@ import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.settingslib.R;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.settingslib.widget.AdaptiveOutlineDrawable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -100,6 +108,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
private boolean mIsHearingAidProfileConnectedFail = false;
|
||||
// Group second device for Hearing Aid
|
||||
private CachedBluetoothDevice mSubDevice;
|
||||
@VisibleForTesting
|
||||
LruCache<String, BitmapDrawable> mDrawableCache;
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
@@ -131,6 +141,19 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
mDevice = device;
|
||||
fillData();
|
||||
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
|
||||
initDrawableCache();
|
||||
}
|
||||
|
||||
private void initDrawableCache() {
|
||||
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
|
||||
int cacheSize = maxMemory / 8;
|
||||
|
||||
mDrawableCache = new LruCache<String, BitmapDrawable>(cacheSize) {
|
||||
@Override
|
||||
protected int sizeOf(String key, BitmapDrawable bitmap) {
|
||||
return bitmap.getBitmap().getByteCount() / 1024;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,6 +404,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
if (dev != null) {
|
||||
final boolean successful = dev.removeBond();
|
||||
if (successful) {
|
||||
releaseLruCache();
|
||||
if (BluetoothUtils.D) {
|
||||
Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
|
||||
}
|
||||
@@ -500,7 +524,21 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
dispatchAttributesChanged();
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
if (BluetoothUtils.isAdvancedDetailsHeader(mDevice)) {
|
||||
Uri uri = BluetoothUtils.getUriMetaData(getDevice(),
|
||||
BluetoothDevice.METADATA_MAIN_ICON);
|
||||
if (uri != null && mDrawableCache.get(uri.toString()) == null) {
|
||||
mDrawableCache.put(uri.toString(),
|
||||
(BitmapDrawable) BluetoothUtils.getBtDrawableWithDescription(
|
||||
mContext, this).first);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadUtils.postOnMainThread(() -> {
|
||||
dispatchAttributesChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void setJustDiscovered(boolean justDiscovered) {
|
||||
@@ -1178,4 +1216,28 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
mSubDevice.mJustDiscovered = tmpJustDiscovered;
|
||||
fetchActiveDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached bluetooth icon with description
|
||||
*/
|
||||
public Pair<Drawable, String> getDrawableWithDescription() {
|
||||
Uri uri = BluetoothUtils.getUriMetaData(mDevice, BluetoothDevice.METADATA_MAIN_ICON);
|
||||
if (BluetoothUtils.isAdvancedDetailsHeader(mDevice) && uri != null) {
|
||||
BitmapDrawable drawable = mDrawableCache.get(uri.toString());
|
||||
if (drawable != null) {
|
||||
Resources resources = mContext.getResources();
|
||||
return new Pair<>(new AdaptiveOutlineDrawable(
|
||||
resources, drawable.getBitmap()),
|
||||
BluetoothUtils.getBtClassDrawableWithDescription(mContext, this).second);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
return BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, this);
|
||||
}
|
||||
|
||||
void releaseLruCache() {
|
||||
mDrawableCache.evictAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.media.AudioManager;
|
||||
|
||||
import com.android.settingslib.R;
|
||||
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
|
||||
import com.android.settingslib.widget.AdaptiveOutlineDrawable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -957,4 +958,41 @@ public class CachedBluetoothDeviceTest {
|
||||
|
||||
// Should not crash
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon() {
|
||||
when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
|
||||
.thenReturn("fake_uri".getBytes());
|
||||
when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||
.thenReturn("true".getBytes());
|
||||
|
||||
mCachedDevice.refresh();
|
||||
|
||||
assertThat(mCachedDevice.getDrawableWithDescription().first).isInstanceOf(
|
||||
AdaptiveOutlineDrawable.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDrawableWithDescription_isNotAdvancedDevice_returnBluetoothIcon() {
|
||||
when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||
.thenReturn("false".getBytes());
|
||||
|
||||
mCachedDevice.refresh();
|
||||
|
||||
assertThat(mCachedDevice.getDrawableWithDescription().first).isNotInstanceOf(
|
||||
AdaptiveOutlineDrawable.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseLruCache_lruCacheShouldBeRelease() {
|
||||
when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
|
||||
.thenReturn("fake_uri".getBytes());
|
||||
when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
|
||||
.thenReturn("true".getBytes());
|
||||
|
||||
mCachedDevice.refresh();
|
||||
mCachedDevice.releaseLruCache();
|
||||
|
||||
assertThat(mCachedDevice.mDrawableCache.size()).isEqualTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user