Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c59b1057 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use LruCache to cache advanced bluetooth deivce icon" into sc-dev

parents dda04945 3a824856
Loading
Loading
Loading
Loading
+63 −1
Original line number Diff line number Diff line
@@ -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() {
        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();
    }
}
+38 −0
Original line number Diff line number Diff line
@@ -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);
    }
}