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