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

Commit cc7b8605 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fixing lock during RecentsModel initialization" into ub-launcher3-master

parents 95786e07 10759887
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ public class OverviewCommandHelper {

    private final Context mContext;
    private final RecentsAnimationDeviceState mDeviceState;
    private final RecentsModel mRecentsModel;
    private final OverviewComponentObserver mOverviewComponentObserver;

    private long mLastToggleTime;
@@ -55,7 +54,6 @@ public class OverviewCommandHelper {
            OverviewComponentObserver observer) {
        mContext = context;
        mDeviceState = deviceState;
        mRecentsModel = RecentsModel.INSTANCE.get(mContext);
        mOverviewComponentObserver = observer;
    }

@@ -158,7 +156,7 @@ public class OverviewCommandHelper {
                    ActivityManagerWrapper.getInstance().getRunningTask(), mDeviceState);

            // Preload the plan
            mRecentsModel.getTasks(null);
            RecentsModel.INSTANCE.get(mContext).getTasks(null);
        }

        @Override
+8 −6
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.quickstep;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.createAndStartNewLooper;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;

import android.annotation.TargetApi;
@@ -26,11 +25,11 @@ import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.os.Build;
import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;

import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -40,6 +39,8 @@ import com.android.systemui.shared.system.TaskStackChangeListener;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

/**
@@ -52,6 +53,9 @@ public class RecentsModel extends TaskStackChangeListener {
    public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
            new MainThreadInitializedObject<>(RecentsModel::new);

    private static final Executor RECENTS_MODEL_EXECUTOR = Executors.newSingleThreadExecutor(
            new SimpleThreadFactory("TaskThumbnailIconCache-", THREAD_PRIORITY_BACKGROUND));

    private final List<TaskVisualsChangeListener> mThumbnailChangeListeners = new ArrayList<>();
    private final Context mContext;

@@ -61,12 +65,10 @@ public class RecentsModel extends TaskStackChangeListener {

    private RecentsModel(Context context) {
        mContext = context;
        Looper looper =
                createAndStartNewLooper("TaskThumbnailIconCache", THREAD_PRIORITY_BACKGROUND);
        mTaskList = new RecentTasksList(MAIN_EXECUTOR,
                new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
        mIconCache = new TaskIconCache(context, looper);
        mThumbnailCache = new TaskThumbnailCache(context, looper);
        mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR);
        mThumbnailCache = new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR);

        ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
        IconProvider.registerIconChangeListener(context,
+18 −32
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.quickstep;

import static com.android.launcher3.FastBitmapDrawable.newIcon;
import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;

import android.app.ActivityManager.TaskDescription;
import android.content.Context;
@@ -27,8 +26,6 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityManager;
@@ -37,12 +34,11 @@ import androidx.annotation.WorkerThread;

import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -50,6 +46,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskDescriptionCompat;

import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
@@ -57,7 +54,7 @@ import java.util.function.Consumer;
 */
public class TaskIconCache {

    private final Handler mBackgroundHandler;
    private final Executor mBgExecutor;
    private final AccessibilityManager mAccessibilityManager;

    private final Context mContext;
@@ -65,9 +62,9 @@ public class TaskIconCache {
    private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
    private final IconProvider mIconProvider;

    public TaskIconCache(Context context, Looper backgroundLooper) {
    public TaskIconCache(Context context, Executor bgExecutor) {
        mContext = context;
        mBackgroundHandler = new Handler(backgroundLooper);
        mBgExecutor = bgExecutor;
        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);

        Resources res = context.getResources();
@@ -83,31 +80,27 @@ public class TaskIconCache {
     * @param callback The callback to receive the task after its data has been populated.
     * @return A cancelable handle to the request
     */
    public IconLoadRequest updateIconInBackground(Task task, Consumer<Task> callback) {
    public CancellableTask updateIconInBackground(Task task, Consumer<Task> callback) {
        Preconditions.assertUIThread();
        if (task.icon != null) {
            // Nothing to load, the icon is already loaded
            callback.accept(task);
            return null;
        }
        CancellableTask<TaskCacheEntry> request = new CancellableTask<TaskCacheEntry>() {
            @Override
            public TaskCacheEntry getResultOnBg() {
                return getCacheEntry(task);
            }

        IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) {
            @Override
            public void run() {
                TaskCacheEntry entry = getCacheEntry(task);
                if (isCanceled()) {
                    // We don't call back to the provided callback in this case
                    return;
                }
                MAIN_EXECUTOR.execute(() -> {
                    task.icon = entry.icon;
                    task.titleDescription = entry.contentDescription;
            public void handleResult(TaskCacheEntry result) {
                task.icon = result.icon;
                task.titleDescription = result.contentDescription;
                callback.accept(task);
                    onEnd();
                });
            }
        };
        Utilities.postAsyncCallback(mBackgroundHandler, request);
        mBgExecutor.execute(request);
        return request;
    }

@@ -120,8 +113,7 @@ public class TaskIconCache {
    }

    void invalidateCacheEntries(String pkg, UserHandle handle) {
        Utilities.postAsyncCallback(mBackgroundHandler,
                () -> mIconCache.removeAll(key ->
        mBgExecutor.execute(() -> mIconCache.removeAll(key ->
                pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
    }

@@ -208,12 +200,6 @@ public class TaskIconCache {
        }
    }

    public static abstract class IconLoadRequest extends HandlerRunnable {
        IconLoadRequest(Handler handler) {
            super(handler, null);
        }
    }

    private static class TaskCacheEntry {
        public Drawable icon;
        public String contentDescription = "";
+16 −36
Original line number Diff line number Diff line
@@ -15,17 +15,12 @@
 */
package com.android.quickstep;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;

import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;

import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -33,11 +28,12 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;

import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

public class TaskThumbnailCache {

    private final Handler mBackgroundHandler;
    private final Executor mBgExecutor;

    private final int mCacheSize;
    private final TaskKeyLruCache<ThumbnailData> mCache;
@@ -94,8 +90,8 @@ public class TaskThumbnailCache {
        }
    }

    public TaskThumbnailCache(Context context, Looper backgroundLooper) {
        mBackgroundHandler = new Handler(backgroundLooper);
    public TaskThumbnailCache(Context context, Executor bgExecutor) {
        mBgExecutor = bgExecutor;
        mHighResLoadingState = new HighResLoadingState(context);

        Resources res = context.getResources();
@@ -130,7 +126,7 @@ public class TaskThumbnailCache {
     * @param callback The callback to receive the task after its data has been populated.
     * @return A cancelable handle to the request
     */
    public ThumbnailLoadRequest updateThumbnailInBackground(
    public CancellableTask updateThumbnailInBackground(
            Task task, Consumer<ThumbnailData> callback) {
        Preconditions.assertUIThread();

@@ -142,14 +138,13 @@ public class TaskThumbnailCache {
            return null;
        }


        return updateThumbnailInBackground(task.key, !mHighResLoadingState.isEnabled(), t -> {
            task.thumbnail = t;
            callback.accept(t);
        });
    }

    private ThumbnailLoadRequest updateThumbnailInBackground(TaskKey key, boolean lowResolution,
    private CancellableTask updateThumbnailInBackground(TaskKey key, boolean lowResolution,
            Consumer<ThumbnailData> callback) {
        Preconditions.assertUIThread();

@@ -160,26 +155,20 @@ public class TaskThumbnailCache {
            return null;
        }

        ThumbnailLoadRequest request = new ThumbnailLoadRequest(mBackgroundHandler,
                lowResolution) {
        CancellableTask<ThumbnailData> request = new CancellableTask<ThumbnailData>() {
            @Override
            public void run() {
                ThumbnailData thumbnail = ActivityManagerWrapper.getInstance().getTaskThumbnail(
            public ThumbnailData getResultOnBg() {
                return ActivityManagerWrapper.getInstance().getTaskThumbnail(
                        key.id, lowResolution);

                MAIN_EXECUTOR.execute(() -> {
                    if (isCanceled()) {
                        // We don't call back to the provided callback in this case
                        return;
            }

                    mCache.put(key, thumbnail);
                    callback.accept(thumbnail);
                    onEnd();
                });
            @Override
            public void handleResult(ThumbnailData result) {
                mCache.put(key, result);
                callback.accept(result);
            }
        };
        Utilities.postAsyncCallback(mBackgroundHandler, request);
        mBgExecutor.execute(request);
        return request;
    }

@@ -218,15 +207,6 @@ public class TaskThumbnailCache {
        return mEnableTaskSnapshotPreloading && mHighResLoadingState.mVisible;
    }

    public static abstract class ThumbnailLoadRequest extends HandlerRunnable {
        public final boolean mLowResolution;

        ThumbnailLoadRequest(Handler handler, boolean lowResolution) {
            super(handler, null);
            mLowResolution = lowResolution;
        }
    }

    /**
     * @return Whether device supports low-res thumbnails. Low-res files are an optimization
     * for faster load times of snapshots. Devices can optionally disable low-res files so that
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.quickstep.util;

import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;

import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;

/**
 * Utility class to executore a task on background and post the result on UI thread
 */
public abstract class CancellableTask<T> implements Runnable {

    private boolean mCancelled = false;

    @Override
    public final void run() {
        if (mCancelled) {
            return;
        }
        T result = getResultOnBg();
        if (mCancelled) {
            return;
        }
        MAIN_EXECUTOR.execute(() -> {
            if (mCancelled) {
                return;
            }
            handleResult(result);
        });
    }

    /**
     * Called on the worker thread to process the request. The return object is passed to
     * {@link #handleResult(Object)}
     */
    @WorkerThread
    public abstract T getResultOnBg();

    /**
     * Called on the UI thread to handle the final result.
     * @param result
     */
    @UiThread
    public abstract void handleResult(T result);

    /**
     * Cancels the request. If it is called before {@link #handleResult(Object)}, that method
     * will not be called
     */
    public void cancel() {
        mCancelled = true;
    }
}
Loading