Home | History | Annotate | Download | only in server
      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.ArrayMap;
     28 import android.util.SparseArray;
     29 
     30 import com.android.internal.annotations.GuardedBy;
     31 
     32 import 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  */
     38 public 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