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