Merge "Fixing lock during RecentsModel initialization" into ub-launcher3-master
This commit is contained in:
committed by
Android (Google) Code Review
commit
cc7b860566
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
IconLoadRequest request = new IconLoadRequest(mBackgroundHandler) {
|
||||
CancellableTask<TaskCacheEntry> request = new CancellableTask<TaskCacheEntry>() {
|
||||
@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;
|
||||
callback.accept(task);
|
||||
onEnd();
|
||||
});
|
||||
public TaskCacheEntry getResultOnBg() {
|
||||
return getCacheEntry(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(TaskCacheEntry result) {
|
||||
task.icon = result.icon;
|
||||
task.titleDescription = result.contentDescription;
|
||||
callback.accept(task);
|
||||
}
|
||||
};
|
||||
Utilities.postAsyncCallback(mBackgroundHandler, request);
|
||||
mBgExecutor.execute(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
@@ -120,9 +113,8 @@ public class TaskIconCache {
|
||||
}
|
||||
|
||||
void invalidateCacheEntries(String pkg, UserHandle handle) {
|
||||
Utilities.postAsyncCallback(mBackgroundHandler,
|
||||
() -> mIconCache.removeAll(key ->
|
||||
pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
|
||||
mBgExecutor.execute(() -> mIconCache.removeAll(key ->
|
||||
pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,7 @@ import com.android.quickstep.TaskIconCache;
|
||||
import com.android.quickstep.TaskOverlayFactory;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.util.CancellableTask;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.quickstep.util.TaskCornerRadius;
|
||||
import com.android.quickstep.views.RecentsView.PageCallbacks;
|
||||
@@ -185,8 +186,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
|
||||
private boolean mShowScreenshot;
|
||||
|
||||
// The current background requests to load the task thumbnail and icon
|
||||
private TaskThumbnailCache.ThumbnailLoadRequest mThumbnailLoadRequest;
|
||||
private TaskIconCache.IconLoadRequest mIconLoadRequest;
|
||||
private CancellableTask mThumbnailLoadRequest;
|
||||
private CancellableTask mIconLoadRequest;
|
||||
|
||||
// Order in which the footers appear. Lower order appear below higher order.
|
||||
public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0;
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.os.Looper;
|
||||
import android.os.Process;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Various different executors used in Launcher
|
||||
@@ -83,4 +85,29 @@ public class Executors {
|
||||
*/
|
||||
public static final LooperExecutor MODEL_EXECUTOR =
|
||||
new LooperExecutor(createAndStartNewLooper("launcher-loader"));
|
||||
|
||||
/**
|
||||
* A simple ThreadFactory to set the thread name and priority when used with executors.
|
||||
*/
|
||||
public static class SimpleThreadFactory implements ThreadFactory {
|
||||
|
||||
private final int mPriority;
|
||||
private final String mNamePrefix;
|
||||
|
||||
private final AtomicInteger mCount = new AtomicInteger(0);
|
||||
|
||||
public SimpleThreadFactory(String namePrefix, int priority) {
|
||||
mNamePrefix = namePrefix;
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable runnable) {
|
||||
Thread t = new Thread(() -> {
|
||||
Process.setThreadPriority(mPriority);
|
||||
runnable.run();
|
||||
}, mNamePrefix + mCount.incrementAndGet());
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user