175 lines
6.7 KiB
Java
175 lines
6.7 KiB
Java
package androidx.appcompat.app;
|
|
|
|
import android.content.res.Resources;
|
|
import android.os.Build;
|
|
import android.util.Log;
|
|
import android.util.LongSparseArray;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.RequiresApi;
|
|
import java.lang.reflect.Field;
|
|
import java.util.Map;
|
|
public class ResourcesFlusher {
|
|
private static final String TAG = "ResourcesFlusher";
|
|
private static Field sDrawableCacheField;
|
|
private static boolean sDrawableCacheFieldFetched;
|
|
private static Field sResourcesImplField;
|
|
private static boolean sResourcesImplFieldFetched;
|
|
private static Class<?> sThemedResourceCacheClazz;
|
|
private static boolean sThemedResourceCacheClazzFetched;
|
|
private static Field sThemedResourceCache_mUnthemedEntriesField;
|
|
private static boolean sThemedResourceCache_mUnthemedEntriesFieldFetched;
|
|
|
|
private ResourcesFlusher() {
|
|
}
|
|
|
|
public static void flush(@NonNull Resources resources) {
|
|
int i = Build.VERSION.SDK_INT;
|
|
if (i < 28) {
|
|
if (i >= 24) {
|
|
flushNougats(resources);
|
|
} else if (i >= 23) {
|
|
flushMarshmallows(resources);
|
|
} else {
|
|
flushLollipops(resources);
|
|
}
|
|
}
|
|
}
|
|
|
|
@RequiresApi(21)
|
|
private static void flushLollipops(@NonNull Resources resources) {
|
|
if (!sDrawableCacheFieldFetched) {
|
|
try {
|
|
Field declaredField = Resources.class.getDeclaredField("mDrawableCache");
|
|
sDrawableCacheField = declaredField;
|
|
declaredField.setAccessible(true);
|
|
} catch (NoSuchFieldException e) {
|
|
Log.e(TAG, "Could not retrieve Resources#mDrawableCache field", e);
|
|
}
|
|
sDrawableCacheFieldFetched = true;
|
|
}
|
|
Field field = sDrawableCacheField;
|
|
if (field != null) {
|
|
Map map = null;
|
|
try {
|
|
map = (Map) field.get(resources);
|
|
} catch (IllegalAccessException e2) {
|
|
Log.e(TAG, "Could not retrieve value from Resources#mDrawableCache", e2);
|
|
}
|
|
if (map != null) {
|
|
map.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
@RequiresApi(23)
|
|
private static void flushMarshmallows(@NonNull Resources resources) {
|
|
if (!sDrawableCacheFieldFetched) {
|
|
try {
|
|
Field declaredField = Resources.class.getDeclaredField("mDrawableCache");
|
|
sDrawableCacheField = declaredField;
|
|
declaredField.setAccessible(true);
|
|
} catch (NoSuchFieldException e) {
|
|
Log.e(TAG, "Could not retrieve Resources#mDrawableCache field", e);
|
|
}
|
|
sDrawableCacheFieldFetched = true;
|
|
}
|
|
Object obj = null;
|
|
Field field = sDrawableCacheField;
|
|
if (field != null) {
|
|
try {
|
|
obj = field.get(resources);
|
|
} catch (IllegalAccessException e2) {
|
|
Log.e(TAG, "Could not retrieve value from Resources#mDrawableCache", e2);
|
|
}
|
|
}
|
|
if (obj != null) {
|
|
flushThemedResourcesCache(obj);
|
|
}
|
|
}
|
|
|
|
@RequiresApi(24)
|
|
private static void flushNougats(@NonNull Resources resources) {
|
|
Object obj;
|
|
if (!sResourcesImplFieldFetched) {
|
|
try {
|
|
Field declaredField = Resources.class.getDeclaredField("mResourcesImpl");
|
|
sResourcesImplField = declaredField;
|
|
declaredField.setAccessible(true);
|
|
} catch (NoSuchFieldException e) {
|
|
Log.e(TAG, "Could not retrieve Resources#mResourcesImpl field", e);
|
|
}
|
|
sResourcesImplFieldFetched = true;
|
|
}
|
|
Field field = sResourcesImplField;
|
|
if (field != null) {
|
|
Object obj2 = null;
|
|
try {
|
|
obj = field.get(resources);
|
|
} catch (IllegalAccessException e2) {
|
|
Log.e(TAG, "Could not retrieve value from Resources#mResourcesImpl", e2);
|
|
obj = null;
|
|
}
|
|
if (obj != null) {
|
|
if (!sDrawableCacheFieldFetched) {
|
|
try {
|
|
Field declaredField2 = obj.getClass().getDeclaredField("mDrawableCache");
|
|
sDrawableCacheField = declaredField2;
|
|
declaredField2.setAccessible(true);
|
|
} catch (NoSuchFieldException e3) {
|
|
Log.e(TAG, "Could not retrieve ResourcesImpl#mDrawableCache field", e3);
|
|
}
|
|
sDrawableCacheFieldFetched = true;
|
|
}
|
|
Field field2 = sDrawableCacheField;
|
|
if (field2 != null) {
|
|
try {
|
|
obj2 = field2.get(obj);
|
|
} catch (IllegalAccessException e4) {
|
|
Log.e(TAG, "Could not retrieve value from ResourcesImpl#mDrawableCache", e4);
|
|
}
|
|
}
|
|
if (obj2 != null) {
|
|
flushThemedResourcesCache(obj2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@RequiresApi(16)
|
|
private static void flushThemedResourcesCache(@NonNull Object obj) {
|
|
if (!sThemedResourceCacheClazzFetched) {
|
|
try {
|
|
sThemedResourceCacheClazz = Class.forName("android.content.res.ThemedResourceCache");
|
|
} catch (ClassNotFoundException e) {
|
|
Log.e(TAG, "Could not find ThemedResourceCache class", e);
|
|
}
|
|
sThemedResourceCacheClazzFetched = true;
|
|
}
|
|
Class<?> cls = sThemedResourceCacheClazz;
|
|
if (cls != null) {
|
|
if (!sThemedResourceCache_mUnthemedEntriesFieldFetched) {
|
|
try {
|
|
Field declaredField = cls.getDeclaredField("mUnthemedEntries");
|
|
sThemedResourceCache_mUnthemedEntriesField = declaredField;
|
|
declaredField.setAccessible(true);
|
|
} catch (NoSuchFieldException e2) {
|
|
Log.e(TAG, "Could not retrieve ThemedResourceCache#mUnthemedEntries field", e2);
|
|
}
|
|
sThemedResourceCache_mUnthemedEntriesFieldFetched = true;
|
|
}
|
|
Field field = sThemedResourceCache_mUnthemedEntriesField;
|
|
if (field != null) {
|
|
LongSparseArray longSparseArray = null;
|
|
try {
|
|
longSparseArray = (LongSparseArray) field.get(obj);
|
|
} catch (IllegalAccessException e3) {
|
|
Log.e(TAG, "Could not retrieve value from ThemedResourceCache#mUnthemedEntries", e3);
|
|
}
|
|
if (longSparseArray != null) {
|
|
longSparseArray.clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|