199e53b86eebb605b70dd7591b89bf61a9414ed0eGlenn Kastenpackage com.bumptech.glide.load.engine.cache;
289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.annotation.TargetApi;
489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.app.ActivityManager;
589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.content.Context;
689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.os.Build;
789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.util.DisplayMetrics;
889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectimport android.util.Log;
989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/**
1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * A calculator that tries to intelligently determine cache sizes for a given device based on some constants and the
1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * devices screen density, width, and height.
1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */
1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectpublic class MemorySizeCalculator {
1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    private static final String TAG = "MemorySizeCalculator";
1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
1789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    static final int BYTES_PER_ARGB_8888_PIXEL = 4;
1889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    static final int MEMORY_CACHE_TARGET_SCREENS = 2;
1989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    static final int BITMAP_POOL_TARGET_SCREENS = 3;
2089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2134fb29696b0f3abf61b10f8d053b1f33d501de0aMark Salyzyn    static final float MAX_SIZE_MULTIPLIER = 0.4f;
22c56f3426099a3cf2d07ccff8886050c7fbce140fGlenn Kasten    static final float LOW_MEMORY_MAX_SIZE_MULTIPLIER = 0.33f;
2389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    private final int bitmapPoolSize;
2434fb29696b0f3abf61b10f8d053b1f33d501de0aMark Salyzyn    private final int memoryCacheSize;
252b01f009428797ee9154649411a64b522946e966Andy Hung
269f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten    interface ScreenDimensions {
279f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten        int getWidthPixels();
2889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        int getHeightPixels();
2989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
309f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten
311ab85ec401801ef9a9184650d0f5a1639b45eeb9Glenn Kasten    public MemorySizeCalculator(Context context) {
32a70eef730d7665c9f4b2dfd25faf072785f80a2dDean Wheatley        this((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE),
33e83b55dc29ca16092ba02f36f55fa6e0e37fd78cEric Laurent                new DisplayMetricsScreenDimensions(context.getResources().getDisplayMetrics()));
34cd04484f4837b8ca0041d118286ab6a98e84fc75Andy Hung    }
35ed30470cf0a20c0c1edb2b82075985ccaa6c75c1Ray Essick
36ed30470cf0a20c0c1edb2b82075985ccaa6c75c1Ray Essick    MemorySizeCalculator(ActivityManager activityManager, ScreenDimensions screenDimensions) {
37fce7a473248381cc83a01855f92581077d3c9ee2Dima Zavin        final int maxSize = getMaxSize(activityManager);
38b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald
39b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald        final int screenSize = screenDimensions.getWidthPixels() * screenDimensions.getHeightPixels()
4053c3b5fc1afe162a8669cb3d27d6bb14e1847e39Andy Hung                * BYTES_PER_ARGB_8888_PIXEL;
41511754b5839fd9b09fc56b89ae007fbc39084a33Glenn Kasten
4289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        int targetPoolSize = screenSize * BITMAP_POOL_TARGET_SCREENS;
4333005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh        int targetMemoryCacheSize = screenSize * MEMORY_CACHE_TARGET_SCREENS;
4433005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh
458cf3a0788df2ee184b498086b1b8da322eeadccaIvan Lozano        if (targetMemoryCacheSize + targetPoolSize <= maxSize) {
468cf3a0788df2ee184b498086b1b8da322eeadccaIvan Lozano            memoryCacheSize = targetMemoryCacheSize;
47a7f03353d5f172016f324e2a01f301cca6794152Andy Hung            bitmapPoolSize = targetPoolSize;
48a7f03353d5f172016f324e2a01f301cca6794152Andy Hung        } else {
494ede21d9c1f957baf5e561849ff9bbe4bcbefc20Andy Hung            int part = Math.round((float) maxSize / (BITMAP_POOL_TARGET_SCREENS + MEMORY_CACHE_TARGET_SCREENS));
50a7f03353d5f172016f324e2a01f301cca6794152Andy Hung            memoryCacheSize = part * MEMORY_CACHE_TARGET_SCREENS;
514ede21d9c1f957baf5e561849ff9bbe4bcbefc20Andy Hung            bitmapPoolSize = part * BITMAP_POOL_TARGET_SCREENS;
524ede21d9c1f957baf5e561849ff9bbe4bcbefc20Andy Hung        }
534ede21d9c1f957baf5e561849ff9bbe4bcbefc20Andy Hung
54a7f03353d5f172016f324e2a01f301cca6794152Andy Hung        if (Log.isLoggable(TAG, Log.DEBUG)) {
55a7f03353d5f172016f324e2a01f301cca6794152Andy Hung            Log.d(TAG, "Calculated memory cache size: " + toMb(memoryCacheSize) + " pool size: " + toMb(bitmapPoolSize)
56a7f03353d5f172016f324e2a01f301cca6794152Andy Hung                    + " memory class limited? " + (targetMemoryCacheSize + targetPoolSize > maxSize) + " max size: "
57a7f03353d5f172016f324e2a01f301cca6794152Andy Hung                    + toMb(maxSize) + " memoryClass: " + activityManager.getMemoryClass() + " isLowMemoryDevice: "
58a7f03353d5f172016f324e2a01f301cca6794152Andy Hung                    + isLowMemoryDevice(activityManager));
59a7f03353d5f172016f324e2a01f301cca6794152Andy Hung        }
60a7f03353d5f172016f324e2a01f301cca6794152Andy Hung    }
61a7f03353d5f172016f324e2a01f301cca6794152Andy Hung
62a7f03353d5f172016f324e2a01f301cca6794152Andy Hung    /**
63a7f03353d5f172016f324e2a01f301cca6794152Andy Hung     * Returns the recommended memory cache size for the device it is run on in bytes.
647f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung     */
657f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung    public int getMemoryCacheSize() {
667f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung        return memoryCacheSize;
677f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung    }
687f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung
69ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung    /**
70ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung     * Returns the recommended bitmap pool size for the device it is run on in bytes.
71ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung     */
72ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung    public int getBitmapPoolSize() {
73ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung        return bitmapPoolSize;
74ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung    }
75ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung
76ffa3695a012d22c6c81cf311232c5c84c06f9219Andy Hung    private static int getMaxSize(ActivityManager activityManager) {
777f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung        final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
787f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung        final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
797f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung        return Math.round(memoryClassBytes
807f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung                * (isLowMemoryDevice ? LOW_MEMORY_MAX_SIZE_MULTIPLIER : MAX_SIZE_MULTIPLIER));
817f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung    }
827f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung
837f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung    private static int toMb(int bytes) {
847f1bc8af1c46695191bf7e2aba6467f3616629c0Andy Hung        return bytes / (1024 * 1024);
8526145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung    }
8626145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung
8726145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung    @TargetApi(Build.VERSION_CODES.KITKAT)
8826145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung    private static boolean isLowMemoryDevice(ActivityManager activityManager) {
8926145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        final int sdkInt = Build.VERSION.SDK_INT;
9026145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        return sdkInt < Build.VERSION_CODES.HONEYCOMB
9126145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung                || (sdkInt >= Build.VERSION_CODES.KITKAT && activityManager.isLowRamDevice());
9226145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung    }
9326145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung
9426145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung    private static class DisplayMetricsScreenDimensions implements ScreenDimensions {
956c7f062d3149d6890daaee64828959ad6f61ea54Ricardo Garcia        private final DisplayMetrics displayMetrics;
9626145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung
9726145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        public DisplayMetricsScreenDimensions(DisplayMetrics displayMetrics) {
9826145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung            this.displayMetrics = displayMetrics;
9926145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        }
10026145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung
10126145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        @Override
10226145643ce22d797b3b1675c82c47a2d8c79ecaaAndy Hung        public int getWidthPixels() {
10333005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh            return displayMetrics.widthPixels;
10433005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh        }
105e33054eb968cbf8ccaee1b0ff0301403902deed6Glenn Kasten
106fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten        @Override
10733005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh        public int getHeightPixels() {
10833005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh            return displayMetrics.heightPixels;
109d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten        }
110d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten    }
111d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten}
11204cd0186305e2b59d23c9147787046c6662029ccGlenn Kasten