Home | History | Annotate | Download | only in model
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.systemui.recents.model;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.ComponentCallbacks2;
     21 import android.content.Context;
     22 import android.content.pm.ActivityInfo;
     23 import android.content.res.Resources;
     24 import android.graphics.Bitmap;
     25 import android.graphics.drawable.BitmapDrawable;
     26 import android.graphics.drawable.Drawable;
     27 import android.os.Handler;
     28 import android.os.HandlerThread;
     29 import android.util.Log;
     30 
     31 import com.android.systemui.R;
     32 import com.android.systemui.recents.Constants;
     33 import com.android.systemui.recents.RecentsConfiguration;
     34 import com.android.systemui.recents.misc.SystemServicesProxy;
     35 
     36 import java.util.concurrent.ConcurrentLinkedQueue;
     37 
     38 
     39 /** Handle to an ActivityInfo */
     40 class ActivityInfoHandle {
     41     ActivityInfo info;
     42 }
     43 
     44 /** A bitmap load queue */
     45 class TaskResourceLoadQueue {
     46     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
     47 
     48     /** Adds a new task to the load queue */
     49     void addTask(Task t) {
     50         if (!mQueue.contains(t)) {
     51             mQueue.add(t);
     52         }
     53         synchronized(this) {
     54             notifyAll();
     55         }
     56     }
     57 
     58     /**
     59      * Retrieves the next task from the load queue, as well as whether we want that task to be
     60      * force reloaded.
     61      */
     62     Task nextTask() {
     63         return mQueue.poll();
     64     }
     65 
     66     /** Removes a task from the load queue */
     67     void removeTask(Task t) {
     68         mQueue.remove(t);
     69     }
     70 
     71     /** Clears all the tasks from the load queue */
     72     void clearTasks() {
     73         mQueue.clear();
     74     }
     75 
     76     /** Returns whether the load queue is empty */
     77     boolean isEmpty() {
     78         return mQueue.isEmpty();
     79     }
     80 }
     81 
     82 /* Task resource loader */
     83 class TaskResourceLoader implements Runnable {
     84     static String TAG = "TaskResourceLoader";
     85     static boolean DEBUG = false;
     86 
     87     Context mContext;
     88     HandlerThread mLoadThread;
     89     Handler mLoadThreadHandler;
     90     Handler mMainThreadHandler;
     91 
     92     SystemServicesProxy mSystemServicesProxy;
     93     TaskResourceLoadQueue mLoadQueue;
     94     DrawableLruCache mApplicationIconCache;
     95     BitmapLruCache mThumbnailCache;
     96     Bitmap mDefaultThumbnail;
     97     BitmapDrawable mDefaultApplicationIcon;
     98 
     99     boolean mCancelled;
    100     boolean mWaitingOnLoadQueue;
    101 
    102     /** Constructor, creates a new loading thread that loads task resources in the background */
    103     public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache applicationIconCache,
    104                               BitmapLruCache thumbnailCache, Bitmap defaultThumbnail,
    105                               BitmapDrawable defaultApplicationIcon) {
    106         mLoadQueue = loadQueue;
    107         mApplicationIconCache = applicationIconCache;
    108         mThumbnailCache = thumbnailCache;
    109         mDefaultThumbnail = defaultThumbnail;
    110         mDefaultApplicationIcon = defaultApplicationIcon;
    111         mMainThreadHandler = new Handler();
    112         mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
    113                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
    114         mLoadThread.start();
    115         mLoadThreadHandler = new Handler(mLoadThread.getLooper());
    116         mLoadThreadHandler.post(this);
    117     }
    118 
    119     /** Restarts the loader thread */
    120     void start(Context context) {
    121         mContext = context;
    122         mCancelled = false;
    123         mSystemServicesProxy = new SystemServicesProxy(context);
    124         // Notify the load thread to start loading
    125         synchronized(mLoadThread) {
    126             mLoadThread.notifyAll();
    127         }
    128     }
    129 
    130     /** Requests the loader thread to stop after the current iteration */
    131     void stop() {
    132         // Mark as cancelled for the thread to pick up
    133         mCancelled = true;
    134         mSystemServicesProxy = null;
    135         // If we are waiting for the load queue for more tasks, then we can just reset the
    136         // Context now, since nothing is using it
    137         if (mWaitingOnLoadQueue) {
    138             mContext = null;
    139         }
    140     }
    141 
    142     @Override
    143     public void run() {
    144         while (true) {
    145             if (mCancelled) {
    146                 // We have to unset the context here, since the background thread may be using it
    147                 // when we call stop()
    148                 mContext = null;
    149                 // If we are cancelled, then wait until we are started again
    150                 synchronized(mLoadThread) {
    151                     try {
    152                         mLoadThread.wait();
    153                     } catch (InterruptedException ie) {
    154                         ie.printStackTrace();
    155                     }
    156                 }
    157             } else {
    158                 RecentsConfiguration config = RecentsConfiguration.getInstance();
    159                 SystemServicesProxy ssp = mSystemServicesProxy;
    160                 // If we've stopped the loader, then fall through to the above logic to wait on
    161                 // the load thread
    162                 if (ssp != null) {
    163                     // Load the next item from the queue
    164                     final Task t = mLoadQueue.nextTask();
    165                     if (t != null) {
    166                         Drawable cachedIcon = mApplicationIconCache.get(t.key);
    167                         Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
    168 
    169                         // Load the application icon if it is stale or we haven't cached one yet
    170                         if (cachedIcon == null) {
    171                             cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
    172                                     mContext.getResources());
    173 
    174                             if (cachedIcon == null) {
    175                                 ActivityInfo info = ssp.getActivityInfo(
    176                                         t.key.baseIntent.getComponent(), t.key.userId);
    177                                 if (info != null) {
    178                                     if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
    179                                     cachedIcon = ssp.getActivityIcon(info, t.key.userId);
    180                                 }
    181                             }
    182 
    183                             if (cachedIcon == null) {
    184                                 cachedIcon = mDefaultApplicationIcon;
    185                             }
    186 
    187                             // At this point, even if we can't load the icon, we will set the
    188                             // default icon.
    189                             mApplicationIconCache.put(t.key, cachedIcon);
    190                         }
    191                         // Load the thumbnail if it is stale or we haven't cached one yet
    192                         if (cachedThumbnail == null) {
    193                             if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
    194                                 if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
    195                                 cachedThumbnail = ssp.getTaskThumbnail(t.key.id);
    196                             }
    197                             if (cachedThumbnail == null) {
    198                                 cachedThumbnail = mDefaultThumbnail;
    199                             }
    200                             // When svelte, we trim the memory to just the visible thumbnails when
    201                             // leaving, so don't thrash the cache as the user scrolls (just load
    202                             // them from scratch each time)
    203                             if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
    204                                 mThumbnailCache.put(t.key, cachedThumbnail);
    205                             }
    206                         }
    207                         if (!mCancelled) {
    208                             // Notify that the task data has changed
    209                             final Drawable newIcon = cachedIcon;
    210                             final Bitmap newThumbnail = cachedThumbnail == mDefaultThumbnail
    211                                     ? null : cachedThumbnail;
    212                             mMainThreadHandler.post(new Runnable() {
    213                                 @Override
    214                                 public void run() {
    215                                     t.notifyTaskDataLoaded(newThumbnail, newIcon);
    216                                 }
    217                             });
    218                         }
    219                     }
    220                 }
    221 
    222                 // If there are no other items in the list, then just wait until something is added
    223                 if (!mCancelled && mLoadQueue.isEmpty()) {
    224                     synchronized(mLoadQueue) {
    225                         try {
    226                             mWaitingOnLoadQueue = true;
    227                             mLoadQueue.wait();
    228                             mWaitingOnLoadQueue = false;
    229                         } catch (InterruptedException ie) {
    230                             ie.printStackTrace();
    231                         }
    232                     }
    233                 }
    234             }
    235         }
    236     }
    237 
    238     Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
    239             SystemServicesProxy ssp, Resources res) {
    240         Bitmap tdIcon = iconBitmap != null
    241                 ? iconBitmap
    242                 : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
    243         if (tdIcon != null) {
    244             return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
    245         }
    246         return null;
    247     }
    248 }
    249 
    250 /* Recents task loader
    251  * NOTE: We should not hold any references to a Context from a static instance */
    252 public class RecentsTaskLoader {
    253     private static final String TAG = "RecentsTaskLoader";
    254 
    255     static RecentsTaskLoader sInstance;
    256     static int INVALID_TASK_ID = -1;
    257 
    258     SystemServicesProxy mSystemServicesProxy;
    259     DrawableLruCache mApplicationIconCache;
    260     BitmapLruCache mThumbnailCache;
    261     StringLruCache mActivityLabelCache;
    262     StringLruCache mContentDescriptionCache;
    263     TaskResourceLoadQueue mLoadQueue;
    264     TaskResourceLoader mLoader;
    265 
    266     RecentsPackageMonitor mPackageMonitor;
    267 
    268     int mMaxThumbnailCacheSize;
    269     int mMaxIconCacheSize;
    270     int mNumVisibleTasksLoaded;
    271     int mNumVisibleThumbnailsLoaded;
    272 
    273     BitmapDrawable mDefaultApplicationIcon;
    274     Bitmap mDefaultThumbnail;
    275 
    276     /** Private Constructor */
    277     private RecentsTaskLoader(Context context) {
    278         mMaxThumbnailCacheSize = context.getResources().getInteger(
    279                 R.integer.config_recents_max_thumbnail_count);
    280         mMaxIconCacheSize = context.getResources().getInteger(
    281                 R.integer.config_recents_max_icon_count);
    282         int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
    283                 mMaxIconCacheSize;
    284         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
    285                 mMaxThumbnailCacheSize;
    286 
    287         // Create the default assets
    288         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
    289         icon.eraseColor(0x00000000);
    290         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
    291         mDefaultThumbnail.setHasAlpha(false);
    292         mDefaultThumbnail.eraseColor(0xFFffffff);
    293         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
    294 
    295         // Initialize the proxy, cache and loaders
    296         mSystemServicesProxy = new SystemServicesProxy(context);
    297         mPackageMonitor = new RecentsPackageMonitor();
    298         mLoadQueue = new TaskResourceLoadQueue();
    299         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
    300         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
    301         mActivityLabelCache = new StringLruCache(100);
    302         mContentDescriptionCache = new StringLruCache(100);
    303         mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
    304                 mDefaultThumbnail, mDefaultApplicationIcon);
    305     }
    306 
    307     /** Initializes the recents task loader */
    308     public static RecentsTaskLoader initialize(Context context) {
    309         if (sInstance == null) {
    310             sInstance = new RecentsTaskLoader(context);
    311         }
    312         return sInstance;
    313     }
    314 
    315     /** Returns the current recents task loader */
    316     public static RecentsTaskLoader getInstance() {
    317         return sInstance;
    318     }
    319 
    320     /** Returns the system services proxy */
    321     public SystemServicesProxy getSystemServicesProxy() {
    322         return mSystemServicesProxy;
    323     }
    324 
    325     /** Returns the activity label using as many cached values as we can. */
    326     public String getAndUpdateActivityLabel(Task.TaskKey taskKey,
    327             ActivityManager.TaskDescription td, SystemServicesProxy ssp,
    328             ActivityInfoHandle infoHandle) {
    329         // Return the task description label if it exists
    330         if (td != null && td.getLabel() != null) {
    331             return td.getLabel();
    332         }
    333         // Return the cached activity label if it exists
    334         String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
    335         if (label != null) {
    336             return label;
    337         }
    338         // All short paths failed, load the label from the activity info and cache it
    339         if (infoHandle.info == null) {
    340             infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
    341                     taskKey.userId);
    342         }
    343         if (infoHandle.info != null) {
    344             label = ssp.getActivityLabel(infoHandle.info);
    345             mActivityLabelCache.put(taskKey, label);
    346             return label;
    347         } else {
    348             Log.w(TAG, "Missing ActivityInfo for " + taskKey.baseIntent.getComponent()
    349                     + " u=" + taskKey.userId);
    350         }
    351         // If the activity info does not exist or fails to load, return an empty label for now,
    352         // but do not cache it
    353         return "";
    354     }
    355 
    356     /** Returns the content description using as many cached values as we can. */
    357     public String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
    358             SystemServicesProxy ssp, Resources res) {
    359         // Return the cached content description if it exists
    360         String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
    361         if (label != null) {
    362             return label;
    363         }
    364         // If the given activity label is empty, don't compute or cache the content description
    365         if (activityLabel.isEmpty()) {
    366             return "";
    367         }
    368 
    369         label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
    370         if (label != null) {
    371             mContentDescriptionCache.put(taskKey, label);
    372             return label;
    373         } else {
    374             Log.w(TAG, "Missing content description for " + taskKey.baseIntent.getComponent()
    375                     + " u=" + taskKey.userId);
    376         }
    377         // If the content description does not exist, return an empty label for now, but do not
    378         // cache it
    379         return "";
    380     }
    381 
    382     /** Returns the activity icon using as many cached values as we can. */
    383     public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
    384             ActivityManager.TaskDescription td, SystemServicesProxy ssp,
    385             Resources res, ActivityInfoHandle infoHandle, boolean loadIfNotCached) {
    386         // Return the cached activity icon if it exists
    387         Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
    388         if (icon != null) {
    389             return icon;
    390         }
    391 
    392         if (loadIfNotCached) {
    393             // Return and cache the task description icon if it exists
    394             Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
    395                     td.getIconFilename(), ssp, res);
    396             if (tdDrawable != null) {
    397                 mApplicationIconCache.put(taskKey, tdDrawable);
    398                 return tdDrawable;
    399             }
    400 
    401             // Load the icon from the activity info and cache it
    402             if (infoHandle.info == null) {
    403                 infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
    404                         taskKey.userId);
    405             }
    406             if (infoHandle.info != null) {
    407                 icon = ssp.getActivityIcon(infoHandle.info, taskKey.userId);
    408                 if (icon != null) {
    409                     mApplicationIconCache.put(taskKey, icon);
    410                     return icon;
    411                 }
    412             }
    413         }
    414         // We couldn't load any icon
    415         return null;
    416     }
    417 
    418     /** Returns the bitmap using as many cached values as we can. */
    419     public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, SystemServicesProxy ssp,
    420             boolean loadIfNotCached) {
    421         // Return the cached thumbnail if it exists
    422         Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
    423         if (thumbnail != null) {
    424             return thumbnail;
    425         }
    426 
    427         RecentsConfiguration config = RecentsConfiguration.getInstance();
    428         if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING && loadIfNotCached) {
    429             // Load the thumbnail from the system
    430             thumbnail = ssp.getTaskThumbnail(taskKey.id);
    431             if (thumbnail != null) {
    432                 mThumbnailCache.put(taskKey, thumbnail);
    433                 return thumbnail;
    434             }
    435         }
    436         // We couldn't load any thumbnail
    437         return null;
    438     }
    439 
    440     /** Returns the activity's primary color. */
    441     public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
    442             RecentsConfiguration config) {
    443         if (td != null && td.getPrimaryColor() != 0) {
    444             return td.getPrimaryColor();
    445         }
    446         return config.taskBarViewDefaultBackgroundColor;
    447     }
    448 
    449     /** Returns the size of the app icon cache. */
    450     public int getApplicationIconCacheSize() {
    451         return mMaxIconCacheSize;
    452     }
    453 
    454     /** Returns the size of the thumbnail cache. */
    455     public int getThumbnailCacheSize() {
    456         return mMaxThumbnailCacheSize;
    457     }
    458 
    459     /** Creates a new plan for loading the recent tasks. */
    460     public RecentsTaskLoadPlan createLoadPlan(Context context) {
    461         RecentsConfiguration config = RecentsConfiguration.getInstance();
    462         RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context, config, mSystemServicesProxy);
    463         return plan;
    464     }
    465 
    466     /** Preloads recents tasks using the specified plan to store the output. */
    467     public void preloadTasks(RecentsTaskLoadPlan plan, boolean isTopTaskHome) {
    468         plan.preloadPlan(this, isTopTaskHome);
    469     }
    470 
    471     /** Begins loading the heavy task data according to the specified options. */
    472     public void loadTasks(Context context, RecentsTaskLoadPlan plan,
    473             RecentsTaskLoadPlan.Options opts) {
    474         if (opts == null) {
    475             throw new RuntimeException("Requires load options");
    476         }
    477         plan.executePlan(opts, this, mLoadQueue);
    478         if (!opts.onlyLoadForCache) {
    479             mNumVisibleTasksLoaded = opts.numVisibleTasks;
    480             mNumVisibleThumbnailsLoaded = opts.numVisibleTaskThumbnails;
    481 
    482             // Start the loader
    483             mLoader.start(context);
    484         }
    485     }
    486 
    487     /** Acquires the task resource data directly from the pool. */
    488     public void loadTaskData(Task t) {
    489         Drawable applicationIcon = mApplicationIconCache.getAndInvalidateIfModified(t.key);
    490         Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
    491 
    492         // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
    493         // use the default assets in their place until they load
    494         boolean requiresLoad = (applicationIcon == null) || (thumbnail == null);
    495         applicationIcon = applicationIcon != null ? applicationIcon : mDefaultApplicationIcon;
    496         if (requiresLoad) {
    497             mLoadQueue.addTask(t);
    498         }
    499         t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, applicationIcon);
    500     }
    501 
    502     /** Releases the task resource data back into the pool. */
    503     public void unloadTaskData(Task t) {
    504         mLoadQueue.removeTask(t);
    505         t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
    506     }
    507 
    508     /** Completely removes the resource data from the pool. */
    509     public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
    510         mLoadQueue.removeTask(t);
    511         mThumbnailCache.remove(t.key);
    512         mApplicationIconCache.remove(t.key);
    513         if (notifyTaskDataUnloaded) {
    514             t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
    515         }
    516     }
    517 
    518     /** Stops the task loader and clears all pending tasks */
    519     void stopLoader() {
    520         mLoader.stop();
    521         mLoadQueue.clearTasks();
    522     }
    523 
    524     /** Registers any broadcast receivers. */
    525     public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
    526         // Register the broadcast receiver to handle messages related to packages being added/removed
    527         mPackageMonitor.register(context, cb);
    528     }
    529 
    530     /** Unregisters any broadcast receivers. */
    531     public void unregisterReceivers() {
    532         mPackageMonitor.unregister();
    533     }
    534 
    535     /**
    536      * Handles signals from the system, trimming memory when requested to prevent us from running
    537      * out of memory.
    538      */
    539     public void onTrimMemory(int level) {
    540         RecentsConfiguration config = RecentsConfiguration.getInstance();
    541         switch (level) {
    542             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
    543                 // Stop the loader immediately when the UI is no longer visible
    544                 stopLoader();
    545                 if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
    546                     mThumbnailCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
    547                             mMaxThumbnailCacheSize / 2));
    548                 } else if (config.svelteLevel == RecentsConfiguration.SVELTE_LIMIT_CACHE) {
    549                     mThumbnailCache.trimToSize(mNumVisibleThumbnailsLoaded);
    550                 } else if (config.svelteLevel >= RecentsConfiguration.SVELTE_DISABLE_CACHE) {
    551                     mThumbnailCache.evictAll();
    552                 }
    553                 mApplicationIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
    554                         mMaxIconCacheSize / 2));
    555                 break;
    556             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
    557             case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
    558                 // We are leaving recents, so trim the data a bit
    559                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 2));
    560                 mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
    561                 break;
    562             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
    563             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
    564                 // We are going to be low on memory
    565                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 4));
    566                 mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
    567                 break;
    568             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
    569             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
    570                 // We are low on memory, so release everything
    571                 mThumbnailCache.evictAll();
    572                 mApplicationIconCache.evictAll();
    573                 // The cache is small, only clear the label cache when we are critical
    574                 mActivityLabelCache.evictAll();
    575                 mContentDescriptionCache.evictAll();
    576                 break;
    577             default:
    578                 break;
    579         }
    580     }
    581 }
    582