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

Commit 9f982f56 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Removing some unused classes"

parents d4b9d902 a34e04bb
Loading
Loading
Loading
Loading
+0 −197
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 static android.content.pm.PackageManager.MATCH_ANY_USER;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
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, desc);
        }
        if (desc.getIconResource() != 0) {
            try {
                PackageManager pm = mContext.getPackageManager();
                ApplicationInfo appInfo = pm.getApplicationInfo(taskKey.getPackageName(),
                        MATCH_ANY_USER);
                Resources res = pm.getResourcesForApplication(appInfo);
                return createBadgedDrawable(res.getDrawable(desc.getIconResource(), null), userId,
                        desc);
            } catch (Resources.NotFoundException|PackageManager.NameNotFoundException 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, desc);
        }

        // Load the icon from the activity info and cache it
        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
        if (activityInfo != null) {
            Drawable icon = getBadgedActivityIcon(activityInfo, userId, desc);
            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,
            ActivityManager.TaskDescription desc) {
        return createBadgedDrawable(
                new BitmapDrawable(mContext.getResources(), icon), userId, desc);
    }

    protected abstract Drawable createBadgedDrawable(Drawable icon, int userId,
            ActivityManager.TaskDescription desc);

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

    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,
                ActivityManager.TaskDescription desc) {
            if (userId != UserHandle.myUserId()) {
                icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(userId));
            }
            return icon;
        }

        @Override
        protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId,
                ActivityManager.TaskDescription desc) {
            return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
        }
    }
}
+0 −101
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.util.Log;
import android.util.SparseArray;

import com.android.systemui.shared.recents.model.Task.TaskKey;

import java.util.ArrayList;
import java.util.Collection;

/**
 * Base class for both strong and LRU task key cache.
 */
public abstract class TaskKeyCache<V> {

    protected static final String TAG = "TaskKeyCache";

    protected final SparseArray<TaskKey> mKeys = new SparseArray<>();

    /**
     * Gets a specific entry in the cache with the specified key, regardless of whether the cached
     * value is valid or not.
     */
    public final synchronized V get(TaskKey key) {
        return getCacheEntry(key.id);
    }

    /**
     * Returns the value only if the key is valid (has not been updated since the last time it was
     * in the cache)
     */
    public final synchronized V getAndInvalidateIfModified(TaskKey key) {
        TaskKey lastKey = mKeys.get(key.id);
        if (lastKey != null) {
            if ((lastKey.windowingMode != key.windowingMode) ||
                    (lastKey.lastActiveTime != key.lastActiveTime)) {
                // The task has updated (been made active since the last time it was put into the
                // LRU cache) or the stack id for the task has changed, invalidate that cache item
                remove(key);
                return null;
            }
        }
        // Either the task does not exist in the cache, or the last active time is the same as
        // the key specified, so return what is in the cache
        return getCacheEntry(key.id);
    }

    /** Puts an entry in the cache for a specific key. */
    public final synchronized void put(TaskKey key, V value) {
        if (key == null || value == null) {
            Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
            return;
        }
        mKeys.put(key.id, key);
        putCacheEntry(key.id, value);
    }


    /** Removes a cache entry for a specific key. */
    public final synchronized void remove(TaskKey key) {
        // Remove the key after the cache value because we need it to make the callback
        removeCacheEntry(key.id);
        mKeys.remove(key.id);
    }

    /** @return {@link Collection} of {@link TaskKey} */
    public Collection<TaskKey> getValues() {
        Collection<TaskKey> result = new ArrayList<>(mKeys.size());
        for (int i = 0; i < mKeys.size(); i++) {
            result.add(mKeys.valueAt(i));
        }
        return result;
    }

    /** Removes all the entries in the cache. */
    public final synchronized void evictAll() {
        evictAllCache();
        mKeys.clear();
    }

    protected abstract V getCacheEntry(int id);
    protected abstract void putCacheEntry(int id, V value);
    protected abstract void removeCacheEntry(int id);
    protected abstract void evictAllCache();
}
+0 −100
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.util.LruCache;

import com.android.systemui.shared.recents.model.Task.TaskKey;

import java.io.PrintWriter;

/**
 * A mapping of {@link TaskKey} to value, with additional LRU functionality where the least
 * recently referenced key/values will be evicted as more values than the given cache size are
 * inserted.
 *
 * In addition, this also allows the caller to invalidate cached values for keys that have since
 * changed.
 */
public class TaskKeyLruCache<V> extends TaskKeyCache<V> {

    public interface EvictionCallback {
        void onEntryEvicted(TaskKey key);
    }

    private final LruCache<Integer, V> mCache;
    private final EvictionCallback mEvictionCallback;

    public TaskKeyLruCache(int cacheSize) {
        this(cacheSize, null);
    }

    public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) {
        mEvictionCallback = evictionCallback;
        mCache = new LruCache<Integer, V>(cacheSize) {

            @Override
            protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
                if (mEvictionCallback != null && evicted) {
                    mEvictionCallback.onEntryEvicted(mKeys.get(taskId));
                }

                // Only remove from mKeys on cache remove, not a cache update.
                if (newV == null) {
                    mKeys.remove(taskId);
                }
            }
        };
    }

    /** Trims the cache to a specific size */
    public final void trimToSize(int cacheSize) {
        mCache.trimToSize(cacheSize);
    }

    public void dump(String prefix, PrintWriter writer) {
        String innerPrefix = prefix + "  ";

        writer.print(prefix); writer.print(TAG);
        writer.print(" numEntries="); writer.print(mKeys.size());
        writer.println();
        int keyCount = mKeys.size();
        for (int i = 0; i < keyCount; i++) {
            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
        }
    }

    @Override
    protected V getCacheEntry(int id) {
        return mCache.get(id);
    }

    @Override
    protected void putCacheEntry(int id, V value) {
        mCache.put(id, value);
    }

    @Override
    protected void removeCacheEntry(int id) {
        mCache.remove(id);
    }

    @Override
    protected void evictAllCache() {
        mCache.evictAll();
    }
}
+0 −140
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNull;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.test.suitebuilder.annotation.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

@SmallTest
@RunWith(MockitoJUnitRunner.class)
public class TaskKeyLruCacheTest extends SysuiTestCase {
    private static int sCacheSize = 3;
    private static int sIdTask1 = 1;
    private static int sIdTask2 = 2;
    private static int sIdTask3 = 3;
    private static int sIdUser1 = 1;

    TaskKeyLruCache.EvictionCallback mEvictionCallback;

    TaskKeyLruCache<Integer> mCache;
    private Task.TaskKey mKey1;
    private Task.TaskKey mKey2;
    private Task.TaskKey mKey3;

    @Before
    public void setup() {
        mEvictionCallback = mock(TaskKeyLruCache.EvictionCallback.class);
        mCache = new TaskKeyLruCache<>(sCacheSize, mEvictionCallback);

        mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis());
        mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis());
        mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis());
    }

    @Test
    public void addSingleItem_get_success() {
        mCache.put(mKey1, 1);

        assertEquals(1, (int) mCache.get(mKey1));
    }

    @Test
    public void addSingleItem_getUninsertedItem_returnsNull() {
        mCache.put(mKey1, 1);

        assertNull(mCache.get(mKey2));
    }

    @Test
    public void emptyCache_get_returnsNull() {
        assertNull(mCache.get(mKey1));
    }

    @Test
    public void updateItem_get_returnsSecond() {
        mCache.put(mKey1, 1);
        mCache.put(mKey1, 2);

        assertEquals(2, (int) mCache.get(mKey1));
        assertEquals(1, mCache.mKeys.size());
    }

    @Test
    public void fillCache_put_evictsOldest() {
        mCache.put(mKey1, 1);
        mCache.put(mKey2, 2);
        mCache.put(mKey3, 3);
        Task.TaskKey key4 = new Task.TaskKey(sIdTask3 + 1, 0,
                null, null, sIdUser1, System.currentTimeMillis());
        mCache.put(key4, 4);

        assertNull(mCache.get(mKey1));
        assertEquals(3, mCache.mKeys.size());
        assertEquals(mKey2, mCache.mKeys.valueAt(0));
        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
    }

    @Test
    public void fillCache_remove_success() {
        mCache.put(mKey1, 1);
        mCache.put(mKey2, 2);
        mCache.put(mKey3, 3);

        mCache.remove(mKey2);

        assertNull(mCache.get(mKey2));
        assertEquals(2, mCache.mKeys.size());
        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey2);
    }

    @Test
    public void put_evictionCallback_notCalled() {
        mCache.put(mKey1, 1);
        verify(mEvictionCallback, times(0)).onEntryEvicted(mKey1);
    }

    @Test
    public void evictAll_evictionCallback_called() {
        mCache.put(mKey1, 1);
        mCache.evictAllCache();
        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
    }

    @Test
    public void trimAll_evictionCallback_called() {
        mCache.put(mKey1, 1);
        mCache.put(mKey2, 2);
        mCache.trimToSize(-1);
        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1);
        verify(mEvictionCallback, times(1)).onEntryEvicted(mKey2);

    }
}