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 
18 package com.android.server;
19 
20 import android.content.Context;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageManager;
23 import android.content.res.Configuration;
24 import android.content.res.Resources;
25 import android.content.res.TypedArray;
26 import android.os.UserHandle;
27 import android.util.SparseArray;
28 
29 import java.util.HashMap;
30 import java.util.WeakHashMap;
31 
32 /**
33  * TODO: This should be better integrated into the system so it doesn't need
34  * special calls from the activity manager to clear it.
35  */
36 public final class AttributeCache {
37     private static AttributeCache sInstance = null;
38 
39     private final Context mContext;
40     private final WeakHashMap<String, Package> mPackages =
41             new WeakHashMap<String, Package>();
42     private final Configuration mConfiguration = new Configuration();
43 
44     public final static class Package {
45         public final Context context;
46         private final SparseArray<HashMap<int[], Entry>> mMap
47                 = new SparseArray<HashMap<int[], Entry>>();
48 
Package(Context c)49         public Package(Context c) {
50             context = c;
51         }
52     }
53 
54     public final static class Entry {
55         public final Context context;
56         public final TypedArray array;
57 
Entry(Context c, TypedArray ta)58         public Entry(Context c, TypedArray ta) {
59             context = c;
60             array = ta;
61         }
62     }
63 
init(Context context)64     public static void init(Context context) {
65         if (sInstance == null) {
66             sInstance = new AttributeCache(context);
67         }
68     }
69 
instance()70     public static AttributeCache instance() {
71         return sInstance;
72     }
73 
AttributeCache(Context context)74     public AttributeCache(Context context) {
75         mContext = context;
76     }
77 
removePackage(String packageName)78     public void removePackage(String packageName) {
79         synchronized (this) {
80             mPackages.remove(packageName);
81         }
82     }
83 
updateConfiguration(Configuration config)84     public void updateConfiguration(Configuration config) {
85         synchronized (this) {
86             int changes = mConfiguration.updateFrom(config);
87             if ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE |
88                     ActivityInfo.CONFIG_KEYBOARD_HIDDEN |
89                     ActivityInfo.CONFIG_ORIENTATION)) != 0) {
90                 // The configurations being masked out are ones that commonly
91                 // change so we don't want flushing the cache... all others
92                 // will flush the cache.
93                 mPackages.clear();
94             }
95         }
96     }
97 
get(String packageName, int resId, int[] styleable, int userId)98     public Entry get(String packageName, int resId, int[] styleable, int userId) {
99         synchronized (this) {
100             Package pkg = mPackages.get(packageName);
101             HashMap<int[], Entry> map = null;
102             Entry ent = null;
103             if (pkg != null) {
104                 map = pkg.mMap.get(resId);
105                 if (map != null) {
106                     ent = map.get(styleable);
107                     if (ent != null) {
108                         return ent;
109                     }
110                 }
111             } else {
112                 Context context;
113                 try {
114                     context = mContext.createPackageContextAsUser(packageName, 0,
115                             new UserHandle(userId));
116                     if (context == null) {
117                         return null;
118                     }
119                 } catch (PackageManager.NameNotFoundException e) {
120                     return null;
121                 }
122                 pkg = new Package(context);
123                 mPackages.put(packageName, pkg);
124             }
125 
126             if (map == null) {
127                 map = new HashMap<int[], Entry>();
128                 pkg.mMap.put(resId, map);
129             }
130 
131             try {
132                 ent = new Entry(pkg.context,
133                         pkg.context.obtainStyledAttributes(resId, styleable));
134                 map.put(styleable, ent);
135             } catch (Resources.NotFoundException e) {
136                 return null;
137             }
138 
139             return ent;
140         }
141     }
142 }
143 
144