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.SparseArray;
28
29import java.util.HashMap;
30import 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 */
36public 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
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
58        public Entry(Context c, TypedArray ta) {
59            context = c;
60            array = ta;
61        }
62    }
63
64    public static void init(Context context) {
65        if (sInstance == null) {
66            sInstance = new AttributeCache(context);
67        }
68    }
69
70    public static AttributeCache instance() {
71        return sInstance;
72    }
73
74    public AttributeCache(Context context) {
75        mContext = context;
76    }
77
78    public void removePackage(String packageName) {
79        synchronized (this) {
80            mPackages.remove(packageName);
81        }
82    }
83
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
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