script-astra/Android/Sdk/sources/android-35/com/android/internal/policy/AttributeCache.java

205 lines
6.6 KiB
Java
Raw Normal View History

2025-01-20 15:15:20 +00:00
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.policy;
import android.annotation.RequiresPermission;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.LruCache;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
/**
* TODO: This should be better integrated into the system so it doesn't need
* special calls from the activity manager to clear it.
*/
/** @hide */
public final class AttributeCache {
private static final int CACHE_SIZE = 4;
private static AttributeCache sInstance = null;
private final Context mContext;
@GuardedBy("this")
private final LruCache<String, Package> mPackages = new LruCache<>(CACHE_SIZE);
@GuardedBy("this")
private final Configuration mConfiguration = new Configuration();
private PackageMonitor mPackageMonitor;
public final static class Package {
public final Context context;
private final SparseArray<ArrayMap<int[], Entry>> mMap = new SparseArray<>();
public Package(Context c) {
context = c;
}
}
public final static class Entry {
public final Context context;
public final TypedArray array;
public Entry(Context c, TypedArray ta) {
context = c;
array = ta;
}
void recycle() {
if (array != null) {
array.recycle();
}
}
}
public static void init(Context context) {
if (sInstance == null) {
sInstance = new AttributeCache(context);
}
}
/**
* Start monitor package change, so the resources can be loaded correctly.
*/
void monitorPackageRemove(Handler handler) {
if (mPackageMonitor == null) {
mPackageMonitor = new PackageMonitor(mContext, handler);
}
}
static class PackageMonitor extends BroadcastReceiver {
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
PackageMonitor(Context context, Handler handler) {
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
context.registerReceiverAsUser(this, UserHandle.ALL, filter,
null /* broadcastPermission */, handler);
}
@Override
public void onReceive(Context context, Intent intent) {
final Uri packageUri = intent.getData();
if (packageUri != null) {
final String packageName = packageUri.getEncodedSchemeSpecificPart();
AttributeCache.instance().removePackage(packageName);
}
}
}
public static AttributeCache instance() {
return sInstance;
}
public AttributeCache(Context context) {
mContext = context;
}
public void removePackage(String packageName) {
synchronized (this) {
final Package pkg = mPackages.remove(packageName);
if (pkg != null) {
for (int i = 0; i < pkg.mMap.size(); i++) {
final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i);
for (int j = 0; j < map.size(); j++) {
map.valueAt(j).recycle();
}
}
final Resources res = pkg.context.getResources();
res.flushLayoutCache();
}
}
}
public void updateConfiguration(Configuration config) {
synchronized (this) {
int changes = mConfiguration.updateFrom(config);
if ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE |
ActivityInfo.CONFIG_KEYBOARD_HIDDEN |
ActivityInfo.CONFIG_ORIENTATION)) != 0) {
// The configurations being masked out are ones that commonly
// change so we don't want flushing the cache... all others
// will flush the cache.
mPackages.evictAll();
}
}
}
public Entry get(String packageName, int resId, int[] styleable) {
return get(packageName, resId, styleable, UserHandle.USER_CURRENT);
}
public Entry get(String packageName, int resId, int[] styleable, int userId) {
synchronized (this) {
Package pkg = mPackages.get(packageName);
ArrayMap<int[], Entry> map = null;
Entry ent = null;
if (pkg != null) {
map = pkg.mMap.get(resId);
if (map != null) {
ent = map.get(styleable);
if (ent != null) {
return ent;
}
}
} else {
Context context;
try {
context = mContext.createPackageContextAsUser(packageName, 0,
new UserHandle(userId));
if (context == null) {
return null;
}
} catch (PackageManager.NameNotFoundException e) {
return null;
}
pkg = new Package(context);
mPackages.put(packageName, pkg);
}
if (map == null) {
map = new ArrayMap<>();
pkg.mMap.put(resId, map);
}
try {
ent = new Entry(pkg.context,
pkg.context.obtainStyledAttributes(resId, styleable));
map.put(styleable, ent);
} catch (Resources.NotFoundException e) {
return null;
}
return ent;
}
}
}