205 lines
6.6 KiB
Java
205 lines
6.6 KiB
Java
![]() |
/*
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|