1/* 2** 3** Copyright 2007, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18package com.android.server; 19 20import android.content.Context; 21import android.content.pm.ActivityInfo; 22import android.content.pm.PackageManager; 23import android.content.res.Configuration; 24import android.content.res.Resources; 25import android.content.res.TypedArray; 26import android.os.UserHandle; 27import android.util.ArrayMap; 28import android.util.SparseArray; 29 30import com.android.internal.annotations.GuardedBy; 31 32import java.lang.ref.WeakReference; 33 34/** 35 * TODO: This should be better integrated into the system so it doesn't need 36 * special calls from the activity manager to clear it. 37 */ 38public final class AttributeCache { 39 private static AttributeCache sInstance = null; 40 41 private final Context mContext; 42 43 @GuardedBy("this") 44 private final ArrayMap<String, WeakReference<Package>> mPackages = new ArrayMap<>(); 45 @GuardedBy("this") 46 private final Configuration mConfiguration = new Configuration(); 47 48 public final static class Package { 49 public final Context context; 50 private final SparseArray<ArrayMap<int[], Entry>> mMap = new SparseArray<>(); 51 52 public Package(Context c) { 53 context = c; 54 } 55 } 56 57 public final static class Entry { 58 public final Context context; 59 public final TypedArray array; 60 61 public Entry(Context c, TypedArray ta) { 62 context = c; 63 array = ta; 64 } 65 66 void recycle() { 67 if (array != null) { 68 array.recycle(); 69 } 70 } 71 } 72 73 public static void init(Context context) { 74 if (sInstance == null) { 75 sInstance = new AttributeCache(context); 76 } 77 } 78 79 public static AttributeCache instance() { 80 return sInstance; 81 } 82 83 public AttributeCache(Context context) { 84 mContext = context; 85 } 86 87 public void removePackage(String packageName) { 88 synchronized (this) { 89 final WeakReference<Package> ref = mPackages.remove(packageName); 90 final Package pkg = (ref != null) ? ref.get() : null; 91 if (pkg != null) { 92 if (pkg.mMap != null) { 93 for (int i = 0; i < pkg.mMap.size(); i++) { 94 final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i); 95 for (int j = 0; j < map.size(); j++) { 96 map.valueAt(j).recycle(); 97 } 98 } 99 } 100 101 final Resources res = pkg.context.getResources(); 102 res.flushLayoutCache(); 103 } 104 } 105 } 106 107 public void updateConfiguration(Configuration config) { 108 synchronized (this) { 109 int changes = mConfiguration.updateFrom(config); 110 if ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE | 111 ActivityInfo.CONFIG_KEYBOARD_HIDDEN | 112 ActivityInfo.CONFIG_ORIENTATION)) != 0) { 113 // The configurations being masked out are ones that commonly 114 // change so we don't want flushing the cache... all others 115 // will flush the cache. 116 mPackages.clear(); 117 } 118 } 119 } 120 121 public Entry get(String packageName, int resId, int[] styleable, int userId) { 122 synchronized (this) { 123 WeakReference<Package> ref = mPackages.get(packageName); 124 Package pkg = (ref != null) ? ref.get() : null; 125 ArrayMap<int[], Entry> map = null; 126 Entry ent = null; 127 if (pkg != null) { 128 map = pkg.mMap.get(resId); 129 if (map != null) { 130 ent = map.get(styleable); 131 if (ent != null) { 132 return ent; 133 } 134 } 135 } else { 136 Context context; 137 try { 138 context = mContext.createPackageContextAsUser(packageName, 0, 139 new UserHandle(userId)); 140 if (context == null) { 141 return null; 142 } 143 } catch (PackageManager.NameNotFoundException e) { 144 return null; 145 } 146 pkg = new Package(context); 147 mPackages.put(packageName, new WeakReference<>(pkg)); 148 } 149 150 if (map == null) { 151 map = new ArrayMap<>(); 152 pkg.mMap.put(resId, map); 153 } 154 155 try { 156 ent = new Entry(pkg.context, 157 pkg.context.obtainStyledAttributes(resId, styleable)); 158 map.put(styleable, ent); 159 } catch (Resources.NotFoundException e) { 160 return null; 161 } 162 163 return ent; 164 } 165 } 166} 167 168