Merge "Introduce trimMemory to AppIconCacheManager" am: 10ae330a97 am: f5dd957cf6
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2308424 Change-Id: Ib40ee7d21e04baf0e2f25a4290de506c8aaf4c2c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -22,13 +22,16 @@ import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Cache app icon for management.
|
||||
*/
|
||||
public class AppIconCacheManager {
|
||||
private static final String TAG = "AppIconCacheManager";
|
||||
private static final float CACHE_RATIO = 0.1f;
|
||||
private static final int MAX_CACHE_SIZE_IN_KB = getMaxCacheInKb();
|
||||
@VisibleForTesting
|
||||
static final int MAX_CACHE_SIZE_IN_KB = getMaxCacheInKb();
|
||||
private static final String DELIMITER = ":";
|
||||
private static AppIconCacheManager sAppIconCacheManager;
|
||||
private final LruCache<String, Drawable> mDrawableCache;
|
||||
@@ -109,4 +112,25 @@ public class AppIconCacheManager {
|
||||
private static int getMaxCacheInKb() {
|
||||
return Math.round(CACHE_RATIO * Runtime.getRuntime().maxMemory() / 1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears as much memory as possible.
|
||||
*
|
||||
* @see android.content.ComponentCallbacks2#onTrimMemory(int)
|
||||
*/
|
||||
public void trimMemory(int level) {
|
||||
if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
|
||||
// Time to clear everything
|
||||
if (sAppIconCacheManager != null) {
|
||||
sAppIconCacheManager.mDrawableCache.trimToSize(0);
|
||||
}
|
||||
} else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
|
||||
|| level == android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
|
||||
// Tough time but still affordable, clear half of the cache
|
||||
if (sAppIconCacheManager != null) {
|
||||
final int maxSize = sAppIconCacheManager.mDrawableCache.maxSize();
|
||||
sAppIconCacheManager.mDrawableCache.trimToSize(maxSize / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,21 @@ import org.robolectric.RobolectricTestRunner;
|
||||
public class AppIconCacheManagerTest {
|
||||
|
||||
private static final String APP_PACKAGE_NAME = "com.test.app";
|
||||
private static final String APP_PACKAGE_NAME1 = "com.test.app1";
|
||||
private static final String APP_PACKAGE_NAME2 = "com.test.app2";
|
||||
private static final String APP_PACKAGE_NAME3 = "com.test.app3";
|
||||
private static final int APP_UID = 9999;
|
||||
|
||||
@Mock
|
||||
private Drawable mIcon;
|
||||
|
||||
@Mock
|
||||
private Drawable mIcon1;
|
||||
@Mock
|
||||
private Drawable mIcon2;
|
||||
@Mock
|
||||
private Drawable mIcon3;
|
||||
|
||||
private AppIconCacheManager mAppIconCacheManager;
|
||||
|
||||
@Before
|
||||
@@ -48,6 +58,29 @@ public class AppIconCacheManagerTest {
|
||||
doReturn(10).when(mIcon).getIntrinsicHeight();
|
||||
doReturn(10).when(mIcon).getIntrinsicWidth();
|
||||
doReturn(mIcon).when(mIcon).mutate();
|
||||
|
||||
// Algorithm for trim memory test:
|
||||
// The real maxsize is defined by AppIconCacheManager.MAX_CACHE_SIZE_IN_KB, and the size
|
||||
// of each element is calculated as following:
|
||||
// n * n * 4 / 1024
|
||||
// In the testcase, we want to mock the maxsize of LruCache is 3, so the formula calculating
|
||||
// the size of each element will be like:
|
||||
// n * n * 4 / 1024 = maxsize / 3
|
||||
// Thus, n = square_root(maxsize / 3 * 1024 / 4), which can be used as an icon size.
|
||||
final int iconSize =
|
||||
(int) Math.sqrt(AppIconCacheManager.MAX_CACHE_SIZE_IN_KB / 3f * 1024f / 4f);
|
||||
|
||||
doReturn(iconSize).when(mIcon1).getIntrinsicHeight();
|
||||
doReturn(iconSize).when(mIcon1).getIntrinsicWidth();
|
||||
doReturn(mIcon1).when(mIcon1).mutate();
|
||||
|
||||
doReturn(iconSize).when(mIcon2).getIntrinsicHeight();
|
||||
doReturn(iconSize).when(mIcon2).getIntrinsicWidth();
|
||||
doReturn(mIcon2).when(mIcon2).mutate();
|
||||
|
||||
doReturn(iconSize).when(mIcon3).getIntrinsicHeight();
|
||||
doReturn(iconSize).when(mIcon3).getIntrinsicWidth();
|
||||
doReturn(mIcon3).when(mIcon3).mutate();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -106,4 +139,41 @@ public class AppIconCacheManagerTest {
|
||||
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME, APP_UID)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trimMemory_levelSatisfied_shouldNotCacheIcon() {
|
||||
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME1, APP_UID, mIcon1);
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME2, APP_UID, mIcon2);
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME3, APP_UID, mIcon3);
|
||||
|
||||
// Expected to trim size to 0
|
||||
final int level = android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
|
||||
mAppIconCacheManager.trimMemory(level);
|
||||
|
||||
// None of the elements should be cached
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID)).isNull();
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trimMemory_levelSatisfied_shouldCacheAtLeastHalf() {
|
||||
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME1, APP_UID, mIcon1);
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME2, APP_UID, mIcon2);
|
||||
mAppIconCacheManager.put(APP_PACKAGE_NAME3, APP_UID, mIcon3);
|
||||
|
||||
// Get the last element
|
||||
mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID);
|
||||
|
||||
// Expected to trim size to half of it, which is int( 3 / 2 ) = 1
|
||||
final int level = android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
|
||||
mAppIconCacheManager.trimMemory(level);
|
||||
|
||||
// There should be only one cached element, which is the last recently used one
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID)).isNotNull();
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
|
||||
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user