Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 647b394c authored by Sunny Goyal's avatar Sunny Goyal Committed by Android (Google) Code Review
Browse files

Merge "Extrating out icon generation logic so that it can customized"

parents a72cab84 af42c842
Loading
Loading
Loading
Loading
+5 −37
Original line number Diff line number Diff line
@@ -17,15 +17,12 @@
package com.android.systemui.shared.recents.model;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;

import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;

/**
 * Background task resource loader
@@ -40,8 +37,7 @@ class BackgroundTaskLoader implements Runnable {
    private final Handler mMainThreadHandler;

    private final TaskResourceLoadQueue mLoadQueue;
    private final TaskKeyLruCache<Drawable> mIconCache;
    private final BitmapDrawable mDefaultIcon;
    private final IconLoader mIconLoader;

    private boolean mStarted;
    private boolean mCancelled;
@@ -51,11 +47,9 @@ class BackgroundTaskLoader implements Runnable {

    /** Constructor, creates a new loading thread that loads task resources in the background */
    public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
            TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon,
            OnIdleChangedListener onIdleChangedListener) {
            IconLoader iconLoader, OnIdleChangedListener onIdleChangedListener) {
        mLoadQueue = loadQueue;
        mIconCache = iconCache;
        mDefaultIcon = defaultIcon;
        mIconLoader = iconLoader;
        mMainThreadHandler = new Handler();
        mOnIdleChangedListener = onIdleChangedListener;
        mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
@@ -140,32 +134,7 @@ class BackgroundTaskLoader implements Runnable {
        // Load the next item from the queue
        final Task t = mLoadQueue.nextTask();
        if (t != null) {
            Drawable cachedIcon = mIconCache.get(t.key);

            // Load the icon if it is stale or we haven't cached one yet
            if (cachedIcon == null) {
                cachedIcon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(
                        mContext, t.taskDescription, t.key.userId, mContext.getResources());

                if (cachedIcon == null) {
                    ActivityInfo info = PackageManagerWrapper.getInstance().getActivityInfo(
                            t.key.getComponent(), t.key.userId);
                    if (info != null) {
                        if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
                        cachedIcon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(
                                info, t.key.userId);
                    }
                }

                if (cachedIcon == null) {
                    cachedIcon = mDefaultIcon;
                }

                // At this point, even if we can't load the icon, we will set the
                // default icon.
                mIconCache.put(t.key, cachedIcon);
            }

            final Drawable icon = mIconLoader.getIcon(t);
            if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
            final ThumbnailData thumbnailData =
                    ActivityManagerWrapper.getInstance().getTaskThumbnail(t.key.id,
@@ -173,9 +142,8 @@ class BackgroundTaskLoader implements Runnable {

            if (!mCancelled) {
                // Notify that the task data has changed
                final Drawable finalIcon = cachedIcon;
                mMainThreadHandler.post(
                        () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon));
                        () -> t.notifyTaskDataLoaded(thumbnailData, icon));
            }
        }
    }
+183 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.shared.recents.model;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.LruCache;

import com.android.systemui.shared.system.PackageManagerWrapper;

public abstract class IconLoader {

    private static final String TAG = "IconLoader";

    protected final Context mContext;
    protected final TaskKeyLruCache<Drawable> mIconCache;
    protected final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;

    public IconLoader(Context context, TaskKeyLruCache<Drawable> iconCache, LruCache<ComponentName,
            ActivityInfo> activityInfoCache) {
        mContext = context;
        mIconCache = iconCache;
        mActivityInfoCache = activityInfoCache;
    }

    /**
     * Returns the activity info for the given task key, retrieving one from the system if the
     * task key is expired.
     *
     * TODO: Move this to an ActivityInfoCache class
     */
    public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
        ComponentName cn = taskKey.getComponent();
        ActivityInfo activityInfo = mActivityInfoCache.get(cn);
        if (activityInfo == null) {
            activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId);
            if (cn == null || activityInfo == null) {
                Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " +
                        activityInfo);
                return null;
            }
            mActivityInfoCache.put(cn, activityInfo);
        }
        return activityInfo;
    }

    public Drawable getIcon(Task t) {
        Drawable cachedIcon = mIconCache.get(t.key);
        if (cachedIcon == null) {
            cachedIcon = createNewIconForTask(t.key, t.taskDescription, true /* returnDefault */);
            mIconCache.put(t.key, cachedIcon);
        }
        return cachedIcon;
    }

    /**
     * Returns the cached task icon if the task key is not expired, updating the cache if it is.
     */
    public Drawable getAndInvalidateIfModified(Task.TaskKey taskKey,
            ActivityManager.TaskDescription td, boolean loadIfNotCached) {
        // Return the cached activity icon if it exists
        Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
        if (icon != null) {
            return icon;
        }

        if (loadIfNotCached) {
            icon = createNewIconForTask(taskKey, td, false /* returnDefault */);
            if (icon != null) {
                mIconCache.put(taskKey, icon);
                return icon;
            }
        }

        // We couldn't load any icon
        return null;
    }

    private Drawable createNewIconForTask(Task.TaskKey taskKey,
            ActivityManager.TaskDescription desc, boolean returnDefault) {
        int userId = taskKey.userId;
        Bitmap tdIcon = desc.getInMemoryIcon();
        if (tdIcon != null) {
            return createDrawableFromBitmap(tdIcon, userId);
        }
        if (desc.getIconResource() != 0) {
            // TODO: Use task context here
            try {
                return createBadgedDrawable(mContext.getDrawable(desc.getIconResource()), userId);
            } catch (Resources.NotFoundException e) {
                Log.e(TAG, "Could not find icon drawable from resource", e);
            }
        }

        tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
                desc.getIconFilename(), userId);
        if (tdIcon != null) {
            return createDrawableFromBitmap(tdIcon, userId);
        }

        // Load the icon from the activity info and cache it
        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
        if (activityInfo != null) {
            Drawable icon = getBadgedActivityIcon(activityInfo, userId);
            if (icon != null) {
                return icon;
            }
        }

        // At this point, even if we can't load the icon, we will set the default icon.
        return returnDefault ? getDefaultIcon(userId) : null;
    }

    public abstract Drawable getDefaultIcon(int userId);

    protected Drawable createDrawableFromBitmap(Bitmap icon, int userId) {
        return createBadgedDrawable(new BitmapDrawable(mContext.getResources(), icon), userId);
    }

    protected abstract Drawable createBadgedDrawable(Drawable icon, int userId);

    /**
     * @return the activity icon for the ActivityInfo for a user, badging if necessary.
     */
    protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId);

    public static class DefaultIconLoader extends IconLoader {

        private final BitmapDrawable mDefaultIcon;
        private final IconDrawableFactory mDrawableFactory;

        public DefaultIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
                LruCache<ComponentName, ActivityInfo> activityInfoCache) {
            super(context, iconCache, activityInfoCache);

            // Create the default assets
            Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
            icon.eraseColor(0);
            mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
            mDrawableFactory = IconDrawableFactory.newInstance(context);
        }

        @Override
        public Drawable getDefaultIcon(int userId) {
            return mDefaultIcon;
        }

        @Override
        protected Drawable createBadgedDrawable(Drawable icon, int userId) {
            if (userId != UserHandle.myUserId()) {
                icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(userId));
            }
            return icon;
        }

        @Override
        protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
            return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ public class RecentsTaskLoadPlan {
                    ? loader.getAndUpdateContentDescription(taskKey, t.taskDescription)
                    : "";
            Drawable icon = isStackTask
                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, false)
                    : null;
            ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
                    false /* loadIfNotCached */, false /* storeInCache */);
@@ -179,7 +179,7 @@ public class RecentsTaskLoadPlan {

            if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
                if (task.icon == null) {
                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription, res,
                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
                            true);
                }
            }
+15 −58
Original line number Diff line number Diff line
@@ -21,9 +21,6 @@ import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Looper;
import android.os.Trace;
@@ -36,7 +33,6 @@ import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOpti
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;

import java.io.PrintWriter;
import java.util.Map;
@@ -61,8 +57,6 @@ public class RecentsTaskLoader {
    // Disable all thumbnail loading.
    public static final int SVELTE_DISABLE_LOADING = 3;

    private final Context mContext;

    // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos
    // for many tasks, which we use to get the activity labels and icons.  Unlike the other caches
    // below, this is per-package so we can't invalidate the items in the cache based on the last
@@ -73,6 +67,7 @@ public class RecentsTaskLoader {
    private final TaskKeyLruCache<String> mActivityLabelCache;
    private final TaskKeyLruCache<String> mContentDescriptionCache;
    private final TaskResourceLoadQueue mLoadQueue;
    private final IconLoader mIconLoader;
    private final BackgroundTaskLoader mLoader;
    private final HighResThumbnailLoader mHighResThumbnailLoader;
    @GuardedBy("this")
@@ -86,7 +81,6 @@ public class RecentsTaskLoader {

    private int mDefaultTaskBarBackgroundColor;
    private int mDefaultTaskViewBackgroundColor;
    private final BitmapDrawable mDefaultIcon;

    private EvictionCallback mClearActivityInfoOnEviction = new EvictionCallback() {
        @Override
@@ -99,16 +93,10 @@ public class RecentsTaskLoader {

    public RecentsTaskLoader(Context context, int maxThumbnailCacheSize, int maxIconCacheSize,
            int svelteLevel) {
        mContext = context;
        mMaxThumbnailCacheSize = maxThumbnailCacheSize;
        mMaxIconCacheSize = maxIconCacheSize;
        mSvelteLevel = svelteLevel;

        // Create the default assets
        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
        icon.eraseColor(0);
        mDefaultIcon = new BitmapDrawable(context.getResources(), icon);

        // Initialize the proxy, cache and loaders
        int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
        mHighResThumbnailLoader = new HighResThumbnailLoader(ActivityManagerWrapper.getInstance(),
@@ -119,10 +107,17 @@ public class RecentsTaskLoader {
        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
                mClearActivityInfoOnEviction);
        mActivityInfoCache = new LruCache<>(numRecentTasks);
        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultIcon,

        mIconLoader = createNewIconLoader(context, mIconCache, mActivityInfoCache);
        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconLoader,
                mHighResThumbnailLoader::setTaskLoadQueueIdle);
    }

    protected IconLoader createNewIconLoader(Context context,TaskKeyLruCache<Drawable> iconCache,
            LruCache<ComponentName, ActivityInfo> activityInfoCache) {
        return new IconLoader.DefaultIconLoader(context, iconCache, activityInfoCache);
    }

    /**
     * Sets the default task bar/view colors if none are provided by the app.
     */
@@ -187,7 +182,7 @@ public class RecentsTaskLoader {
     */
    public void loadTaskData(Task t) {
        Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
        icon = icon != null ? icon : mDefaultIcon;
        icon = icon != null ? icon : mIconLoader.getDefaultIcon(t.key.userId);
        mLoadQueue.addTask(t);
        t.notifyTaskDataLoaded(t.thumbnail, icon);
    }
@@ -195,7 +190,7 @@ public class RecentsTaskLoader {
    /** Releases the task resource data back into the pool. */
    public void unloadTaskData(Task t) {
        mLoadQueue.removeTask(t);
        t.notifyTaskDataUnloaded(mDefaultIcon);
        t.notifyTaskDataUnloaded(mIconLoader.getDefaultIcon(t.key.userId));
    }

    /** Completely removes the resource data from the pool. */
@@ -205,7 +200,7 @@ public class RecentsTaskLoader {
        mActivityLabelCache.remove(t.key);
        mContentDescriptionCache.remove(t.key);
        if (notifyTaskDataUnloaded) {
            t.notifyTaskDataUnloaded(mDefaultIcon);
            t.notifyTaskDataUnloaded(mIconLoader.getDefaultIcon(t.key.userId));
        }
    }

@@ -326,35 +321,8 @@ public class RecentsTaskLoader {
     * Returns the cached task icon if the task key is not expired, updating the cache if it is.
     */
    Drawable getAndUpdateActivityIcon(TaskKey taskKey, ActivityManager.TaskDescription td,
            Resources res, boolean loadIfNotCached) {
        // Return the cached activity icon if it exists
        Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
        if (icon != null) {
            return icon;
        }

        if (loadIfNotCached) {
            // Return and cache the task description icon if it exists
            icon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(mContext, td,
                    taskKey.userId, res);
            if (icon != null) {
                mIconCache.put(taskKey, icon);
                return icon;
            }

            // Load the icon from the activity info and cache it
            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
            if (activityInfo != null) {
                icon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(activityInfo,
                        taskKey.userId);
                if (icon != null) {
                    mIconCache.put(taskKey, icon);
                    return icon;
                }
            }
        }
        // We couldn't load any icon
        return null;
            boolean loadIfNotCached) {
        return mIconLoader.getAndInvalidateIfModified(taskKey, td, loadIfNotCached);
    }

    /**
@@ -417,18 +385,7 @@ public class RecentsTaskLoader {
     * task key is expired.
     */
    ActivityInfo getAndUpdateActivityInfo(TaskKey taskKey) {
        ComponentName cn = taskKey.getComponent();
        ActivityInfo activityInfo = mActivityInfoCache.get(cn);
        if (activityInfo == null) {
            activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId);
            if (cn == null || activityInfo == null) {
                Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " +
                        activityInfo);
                return null;
            }
            mActivityInfoCache.put(cn, activityInfo);
        }
        return activityInfo;
        return mIconLoader.getAndUpdateActivityInfo(taskKey);
    }

    /**
+0 −61
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.shared.system;

import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -40,25 +39,19 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;

import android.view.RemoteAnimationTarget;
import android.view.WindowManagerGlobal;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -74,14 +67,12 @@ public class ActivityManagerWrapper {
    private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();

    private final PackageManager mPackageManager;
    private final IconDrawableFactory mDrawableFactory;
    private final BackgroundExecutor mBackgroundExecutor;
    private final TaskStackChangeListeners mTaskStackChangeListeners;

    private ActivityManagerWrapper() {
        final Context context = AppGlobals.getInitialApplication();
        mPackageManager = context.getPackageManager();
        mDrawableFactory = IconDrawableFactory.newInstance(context);
        mBackgroundExecutor = BackgroundExecutor.get();
        mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
    }
@@ -155,58 +146,6 @@ public class ActivityManagerWrapper {
        }
    }

    /**
     * @return the task description icon, loading and badging it if it necessary.
     */
    public Drawable getBadgedTaskDescriptionIcon(Context context,
            ActivityManager.TaskDescription taskDescription, int userId, Resources res) {
        Bitmap tdIcon = taskDescription.getInMemoryIcon();
        Drawable dIcon = null;
        if (tdIcon != null) {
            dIcon = new BitmapDrawable(res, tdIcon);
        } else if (taskDescription.getIconResource() != 0) {
            try {
                dIcon = context.getDrawable(taskDescription.getIconResource());
            } catch (NotFoundException e) {
                Log.e(TAG, "Could not find icon drawable from resource", e);
            }
        } else {
            tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
                    taskDescription.getIconFilename(), userId);
            if (tdIcon != null) {
                dIcon = new BitmapDrawable(res, tdIcon);
            }
        }
        if (dIcon != null) {
            return getBadgedIcon(dIcon, userId);
        }
        return null;
    }

    /**
     * @return the given icon for a user, badging if necessary.
     */
    private Drawable getBadgedIcon(Drawable icon, int userId) {
        if (userId != UserHandle.myUserId()) {
            icon = mPackageManager.getUserBadgedIcon(icon, new UserHandle(userId));
        }
        return icon;
    }

    /**
     * @return the activity icon for the ActivityInfo for a user, badging if necessary.
     */
    public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
        return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
    }

    /**
     * @return the application icon for the ApplicationInfo for a user, badging if necessary.
     */
    public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
        return mDrawableFactory.getBadgedIcon(appInfo, userId);
    }

    /**
     * @return the activity label, badging if necessary.
     */
Loading