diff options
Diffstat (limited to 'quickstep')
36 files changed, 594 insertions, 263 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java index 4ecc39cf6..65e69b604 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java @@ -17,6 +17,8 @@ package com.android.launcher3.appprediction; import static android.content.pm.PackageManager.MATCH_INSTANT; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -30,8 +32,12 @@ import android.os.Message; import android.util.ArrayMap; import android.util.Log; +import androidx.annotation.MainThread; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.annotation.WorkerThread; + import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherIcons; @@ -45,11 +51,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import androidx.annotation.MainThread; -import androidx.annotation.Nullable; -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; - /** * Utility class which loads and caches predicted items like instant apps and shortcuts, before * they can be displayed on the UI @@ -77,7 +78,7 @@ public class DynamicItemCache { public DynamicItemCache(Context context, Runnable onUpdateCallback) { mContext = context; - mWorker = new Handler(LauncherModel.getWorkerLooper(), this::handleWorkerMessage); + mWorker = new Handler(MODEL_EXECUTOR.getLooper(), this::handleWorkerMessage); mUiHandler = new Handler(Looper.getMainLooper(), this::handleUiMessage); mInstantAppResolver = InstantAppResolver.newInstance(context); mOnUpdateCallback = onUpdateCallback; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java index 24fc61bef..4c7943b10 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +16,7 @@ package com.android.launcher3.appprediction; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.annotation.TargetApi; import android.app.prediction.AppPredictionContext; @@ -34,19 +35,25 @@ import android.os.UserHandle; import android.util.Log; import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.annotation.WorkerThread; + import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.model.AppLaunchTracker; -import com.android.launcher3.util.UiThreadHelper; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; +import com.android.systemui.plugins.AppLaunchEventsPlugin; +import com.android.systemui.plugins.PluginListener; -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; +import java.util.ArrayList; +import java.util.List; /** * Subclass of app tracker which publishes the data to the prediction engine and gets back results. */ @TargetApi(Build.VERSION_CODES.Q) -public class PredictionAppTracker extends AppLaunchTracker { +public class PredictionAppTracker extends AppLaunchTracker + implements PluginListener<AppLaunchEventsPlugin> { private static final String TAG = "PredictionAppTracker"; private static final boolean DBG = false; @@ -58,6 +65,7 @@ public class PredictionAppTracker extends AppLaunchTracker { protected final Context mContext; private final Handler mMessageHandler; + private final List<AppLaunchEventsPlugin> mAppLaunchEventsPluginsList; // Accessed only on worker thread private AppPredictor mHomeAppPredictor; @@ -65,10 +73,14 @@ public class PredictionAppTracker extends AppLaunchTracker { public PredictionAppTracker(Context context) { mContext = context; - mMessageHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleMessage); + mMessageHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessage); InvariantDeviceProfile.INSTANCE.get(mContext).addOnChangeListener(this::onIdpChanged); mMessageHandler.sendEmptyMessage(MSG_INIT); + + mAppLaunchEventsPluginsList = new ArrayList<>(); + PluginManagerWrapper.INSTANCE.get(context) + .addPluginListener(this, AppLaunchEventsPlugin.class, true); } @UiThread @@ -96,7 +108,7 @@ public class PredictionAppTracker extends AppLaunchTracker { AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class); if (apm == null) { - return null; + return null; } AppPredictor predictor = apm.createAppPredictionSession( @@ -116,7 +128,7 @@ public class PredictionAppTracker extends AppLaunchTracker { */ @WorkerThread @Nullable - public Bundle getAppPredictionContextExtras(Client client){ + public Bundle getAppPredictionContextExtras(Client client) { return null; } @@ -128,7 +140,7 @@ public class PredictionAppTracker extends AppLaunchTracker { destroy(); // Initialize the clients - int count = InvariantDeviceProfile.INSTANCE.get(mContext).numColumns; + int count = InvariantDeviceProfile.INSTANCE.get(mContext).numAllAppsColumns; mHomeAppPredictor = createPredictor(Client.HOME, count); mRecentsOverviewPredictor = createPredictor(Client.OVERVIEW, count); return true; @@ -167,37 +179,98 @@ public class PredictionAppTracker extends AppLaunchTracker { if (DBG) { Log.d(TAG, String.format("Sent immediate message to update %s", client)); } + + // Relay onReturnedToHome to every plugin. + mAppLaunchEventsPluginsList.forEach(AppLaunchEventsPlugin::onReturnedToHome); } @Override @UiThread public void onStartShortcut(String packageName, String shortcutId, UserHandle user, - String container) { + String container) { // TODO: Use the full shortcut info - AppTarget target = new AppTarget - .Builder(new AppTargetId("shortcut:" + shortcutId), packageName, user) - .setClassName(shortcutId) - .build(); + AppTarget target = new AppTarget.Builder( + new AppTargetId("shortcut:" + shortcutId), packageName, user) + .setClassName(shortcutId) + .build(); + sendLaunch(target, container); + + // Relay onStartShortcut info to every connected plugin. + mAppLaunchEventsPluginsList + .forEach(plugin -> plugin.onStartShortcut( + packageName, + shortcutId, + user, + container != null ? container : CONTAINER_DEFAULT) + ); + } @Override @UiThread public void onStartApp(ComponentName cn, UserHandle user, String container) { if (cn != null) { - AppTarget target = new AppTarget - .Builder(new AppTargetId("app:" + cn), cn.getPackageName(), user) - .setClassName(cn.getClassName()) - .build(); + AppTarget target = new AppTarget.Builder( + new AppTargetId("app:" + cn), cn.getPackageName(), user) + .setClassName(cn.getClassName()) + .build(); sendLaunch(target, container); + + // Relay onStartApp to every connected plugin. + mAppLaunchEventsPluginsList + .forEach(plugin -> plugin.onStartApp( + cn, + user, + container != null ? container : CONTAINER_DEFAULT) + ); } } + @Override @UiThread - private void sendLaunch(AppTarget target, String container) { - AppTargetEvent event = new AppTargetEvent.Builder(target, AppTargetEvent.ACTION_LAUNCH) + public void onDismissApp(ComponentName cn, UserHandle user, String container) { + if (cn == null) return; + AppTarget target = new AppTarget.Builder( + new AppTargetId("app: " + cn), cn.getPackageName(), user) + .setClassName(cn.getClassName()) + .build(); + sendDismiss(target, container); + + // Relay onDismissApp to every connected plugin. + mAppLaunchEventsPluginsList + .forEach(plugin -> plugin.onDismissApp( + cn, + user, + container != null ? container : CONTAINER_DEFAULT) + ); + } + + @UiThread + private void sendEvent(AppTarget target, String container, int eventId) { + AppTargetEvent event = new AppTargetEvent.Builder(target, eventId) .setLaunchLocation(container == null ? CONTAINER_DEFAULT : container) .build(); Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget(); } + + @UiThread + private void sendLaunch(AppTarget target, String container) { + sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH); + } + + @UiThread + private void sendDismiss(AppTarget target, String container) { + sendEvent(target, container, AppTargetEvent.ACTION_DISMISS); + } + + @Override + public void onPluginConnected(AppLaunchEventsPlugin appLaunchEventsPlugin, Context context) { + mAppLaunchEventsPluginsList.add(appLaunchEventsPlugin); + } + + @Override + public void onPluginDisconnected(AppLaunchEventsPlugin appLaunchEventsPlugin) { + mAppLaunchEventsPluginsList.remove(appLaunchEventsPlugin); + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java index 0c7ba9c95..23db5df2e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -43,6 +43,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.allapps.AllAppsStore; @@ -92,7 +93,7 @@ public class PredictionRowView extends LinearLayout implements private final Launcher mLauncher; private final PredictionUiStateManager mPredictionUiStateManager; - private final int mNumPredictedAppsPerRow; + private int mNumPredictedAppsPerRow; // The set of predicted app component names private final List<ComponentKeyMapper> mPredictedAppComponents = new ArrayList<>(); @@ -128,7 +129,7 @@ public class PredictionRowView extends LinearLayout implements mFocusHelper = new SimpleFocusIndicatorHelper(this); - mNumPredictedAppsPerRow = LauncherAppState.getIDP(context).numColumns; + mNumPredictedAppsPerRow = LauncherAppState.getIDP(context).numAllAppsColumns; mLauncher = Launcher.getLauncher(context); mLauncher.addOnDeviceProfileChangeListener(this); @@ -226,6 +227,7 @@ public class PredictionRowView extends LinearLayout implements @Override public void onDeviceProfileChanged(DeviceProfile dp) { + mNumPredictedAppsPerRow = dp.inv.numAllAppsColumns; removeAllViews(); applyPredictionApps(); } @@ -281,7 +283,7 @@ public class PredictionRowView extends LinearLayout implements } private List<ItemInfoWithIcon> processPredictedAppComponents(List<ComponentKeyMapper> components) { - if (getAppsStore().getApps().isEmpty()) { + if (getAppsStore().getApps().length == 0) { // Apps have not been bound yet. return Collections.emptyList(); } @@ -290,7 +292,9 @@ public class PredictionRowView extends LinearLayout implements for (ComponentKeyMapper mapper : components) { ItemInfoWithIcon info = mapper.getApp(getAppsStore()); if (info != null) { - predictedApps.add(info); + ItemInfoWithIcon predictedApp = info.clone(); + predictedApp.container = LauncherSettings.Favorites.CONTAINER_PREDICTION; + predictedApps.add(predictedApp); } else { if (FeatureFlags.IS_DOGFOOD_BUILD) { Log.e(TAG, "Predicted app not found: " + mapper); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 50cfac8e4..468b8afc9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -19,7 +19,6 @@ import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; -import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.LayoutUtils; @@ -69,8 +68,16 @@ public class BackgroundAppState extends OverviewState { if (taskCount == 0) { return super.getOverviewScaleAndTranslation(launcher); } - TaskView dummyTask = recentsView.getTaskViewAt(Utilities.boundToRange( - recentsView.getCurrentPage(), 0, taskCount - 1)); + TaskView dummyTask; + if (recentsView.getCurrentPage() >= 0) { + if (recentsView.getCurrentPage() <= taskCount - 1) { + dummyTask = recentsView.getCurrentPageTaskView(); + } else { + dummyTask = recentsView.getTaskViewAt(taskCount - 1); + } + } else { + dummyTask = recentsView.getTaskViewAt(0); + } return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask) .getScaleAndTranslation(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index ab346c059..4a3ad1d72 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -42,6 +42,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; +import android.view.View; import android.view.ViewConfiguration; import com.android.launcher3.Launcher; @@ -179,6 +180,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { } else { super.onDragEnd(velocity, fling); } + + View searchView = mLauncher.getAppsView().getSearchView(); + if (searchView instanceof FeedbackHandler) { + ((FeedbackHandler) searchView).resetFeedback(); + } mMotionPauseDetector.clear(); } @@ -205,4 +211,16 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW); } } + + /** + * Interface for views with feedback animation requiring reset + */ + public interface FeedbackHandler { + + /** + * reset searchWidget feedback + */ + void resetFeedback(); + } + } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java index 20a248734..03862db1d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java @@ -47,9 +47,9 @@ public final class PortraitOverviewStateTouchHelper { * @return true if we should intercept the motion event */ boolean canInterceptTouch(MotionEvent ev) { - if (mRecentsView.getChildCount() > 0) { + if (mRecentsView.getTaskViewCount() > 0) { // Allow swiping up in the gap between the hotseat and overview. - return ev.getY() >= mRecentsView.getChildAt(0).getBottom(); + return ev.getY() >= mRecentsView.getTaskViewAt(0).getBottom(); } else { // If there are no tasks, we only intercept if we're below the hotseat height. return isTouchOverHotseat(mLauncher, ev); @@ -63,7 +63,7 @@ public final class PortraitOverviewStateTouchHelper { * @return true if going back should take the user to the currently running task */ boolean shouldSwipeDownReturnToApp() { - TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()); + TaskView taskView = mRecentsView.getNextPageTaskView(); return taskView != null && mRecentsView.shouldSwipeDownLaunchApp(); } @@ -76,7 +76,7 @@ public final class PortraitOverviewStateTouchHelper { */ PendingAnimation createSwipeDownToTaskAppAnimation(long duration) { mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen()); - TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getCurrentPage()); + TaskView taskView = mRecentsView.getCurrentPageTaskView(); if (taskView == null) { throw new IllegalStateException("There is no task view to animate to."); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index eb571f607..6576ec573 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -50,7 +50,6 @@ import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.system.QuickStepContract; /** * Handles quick switching to a recent task from the home screen. diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index d627a7f14..7196f7c6f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -22,9 +22,9 @@ import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.anim.Interpolators.ACCEL_1_5; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; -import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR; -import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR; import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import android.animation.Animator; @@ -44,9 +44,10 @@ import android.os.Vibrator; import android.provider.Settings; import android.view.MotionEvent; import android.view.View; -import android.view.WindowManager; import android.view.animation.Interpolator; +import androidx.annotation.UiThread; + import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; @@ -54,7 +55,6 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.Interpolators; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; @@ -75,8 +75,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; import java.util.function.Consumer; -import androidx.annotation.UiThread; - /** * Base class for swipe up handler with some utility methods */ @@ -126,7 +124,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten protected Runnable mGestureEndCallback; - protected final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler(); + protected final Handler mMainThreadHandler = MAIN_EXECUTOR.getHandler(); protected MultiStateCallback mStateCallback; protected boolean mCanceled; @@ -174,7 +172,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten if (effect == null) { return; } - BACKGROUND_EXECUTOR.execute(() -> mVibrator.vibrate(effect)); + UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(effect)); } public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) { @@ -229,10 +227,10 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten // Launch the task user scrolled to (mRecentsView.getNextPage()). if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { // We finish recents animation inside launchTask() when live tile is enabled. - mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */, + mRecentsView.getNextPageTaskView().launchTask(false /* animate */, true /* freezeTaskList */); } else { - int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id; + int taskId = mRecentsView.getNextPageTaskView().getTask().key.id; mFinishingRecentsAnimationForNewTaskId = taskId; mRecentsAnimationWrapper.finish(true /* toRecents */, () -> { if (!mCanceled) { @@ -275,7 +273,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten overviewStackBounds = getStackBounds(dp); } dp.updateInsets(targetSet.homeContentInsets); - dp.updateIsSeascape(mContext.getSystemService(WindowManager.class)); + dp.updateIsSeascape(mContext); if (runningTaskTarget != null) { mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 36eb8a13b..57e6d96ef 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -268,22 +268,12 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0); int runningTaskIndex = recentsView.getRunningTaskIndex(); - if (runningTaskIndex == 0) { + if (runningTaskIndex == recentsView.getTaskViewStartIndex()) { // If we are on the first task (we haven't quick switched), translate recents in // from the side. Calculate the start translation based on current scale/scroll. float currScale = recentsView.getScaleX(); float scrollOffsetX = recentsView.getScrollOffset(); - - float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX; - // The first task is hidden, so offset by its width. - int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth(); - offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale; - // Offset since scale pushes tasks outwards. - offscreenX += firstTaskWidth * (currScale - 1) / 2; - offscreenX = Math.max(0, offscreenX); - if (recentsView.isRtl()) { - offscreenX = -offscreenX; - } + float offscreenX = recentsView.getOffscreenTranslationX(currScale); float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0; float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX; @@ -351,8 +341,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState, LauncherState endState) { RecentsView recentsView = launcher.getOverviewPanel(); - TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage()); - if (v == null) { + if (recentsView.getCurrentPageTaskView() == null) { return; } @@ -380,7 +369,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe // recents as a whole needs to translate further to keep up with the app window. TaskView runningTaskView = recentsView.getRunningTaskView(); if (runningTaskView == null) { - runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage()); + runningTaskView = recentsView.getCurrentPageTaskView(); if (runningTaskView == null) { // There are no task views in LockTask mode when Overview is enabled. return; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index 222ef97d9..a8d402e56 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -15,8 +15,8 @@ */ package com.android.quickstep; -import static com.android.systemui.shared.system.ActivityManagerWrapper - .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -29,7 +29,6 @@ import android.util.Log; import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -49,7 +48,6 @@ public class OverviewCommandHelper { private final Context mContext; private final ActivityManagerWrapper mAM; private final RecentsModel mRecentsModel; - private final MainThreadExecutor mMainThreadExecutor; private final OverviewComponentObserver mOverviewComponentObserver; private long mLastToggleTime; @@ -57,7 +55,6 @@ public class OverviewCommandHelper { public OverviewCommandHelper(Context context, OverviewComponentObserver observer) { mContext = context; mAM = ActivityManagerWrapper.getInstance(); - mMainThreadExecutor = new MainThreadExecutor(); mRecentsModel = RecentsModel.INSTANCE.get(mContext); mOverviewComponentObserver = observer; } @@ -69,19 +66,19 @@ public class OverviewCommandHelper { } mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - mMainThreadExecutor.execute(new RecentsActivityCommand<>()); + MAIN_EXECUTOR.execute(new RecentsActivityCommand<>()); } public void onOverviewShown(boolean triggeredFromAltTab) { - mMainThreadExecutor.execute(new ShowRecentsCommand(triggeredFromAltTab)); + MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab)); } public void onOverviewHidden() { - mMainThreadExecutor.execute(new HideRecentsCommand()); + MAIN_EXECUTOR.execute(new HideRecentsCommand()); } public void onTip(int actionType, int viewType) { - mMainThreadExecutor.execute(() -> + MAIN_EXECUTOR.execute(() -> UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType)); } @@ -112,7 +109,7 @@ public class OverviewCommandHelper { TaskView taskView = rv.getNextTaskView(); if (taskView == null) { if (rv.getTaskViewCount() > 0) { - taskView = (TaskView) rv.getPageAt(0); + taskView = rv.getTaskViewAt(0); taskView.requestFocus(); } else { rv.requestFocus(); @@ -180,7 +177,7 @@ public class OverviewCommandHelper { // Otherwise, start overview. mListener = mHelper.createActivityInitListener(this::onActivityReady); mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(), - this::createWindowAnimation, mContext, mMainThreadExecutor.getHandler(), + this::createWindowAnimation, mContext, MAIN_EXECUTOR.getHandler(), mAnimationProvider.getRecentsLaunchDuration()); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index da4642636..72a14b58e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -1,9 +1,10 @@ package com.android.quickstep; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.os.Bundle; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.states.OverviewState; @@ -52,7 +53,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { case TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN: { try { - final int leftMargin = new MainThreadExecutor().submit(() -> + final int leftMargin = MAIN_EXECUTOR.submit(() -> mLauncher.<RecentsView>getOverviewPanel().getLeftGestureMargin()).get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin); } catch (ExecutionException e) { @@ -65,7 +66,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { case TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN: { try { - final int rightMargin = new MainThreadExecutor().submit(() -> + final int rightMargin = MAIN_EXECUTOR.submit(() -> mLauncher.<RecentsView>getOverviewPanel().getRightGestureMargin()). get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index f08ae4a82..9bdc98bf8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -136,6 +136,12 @@ public final class RecentsActivity extends BaseRecentsActivity { } @Override + public void returnToHomescreen() { + super.returnToHomescreen(); + // TODO(b/137318995) This should go home, but doing so removes freeform windows + } + + @Override public ActivityOptions getActivityLaunchOptions(final View v) { if (!(v instanceof TaskView)) { return null; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java index c55f656df..8783ee3cc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java @@ -15,7 +15,7 @@ */ package com.android.quickstep; -import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.util.Log; @@ -25,6 +25,7 @@ import com.android.launcher3.util.Preconditions; import com.android.quickstep.util.RecentsAnimationListenerSet; import com.android.quickstep.util.SwipeAnimationTargetSet; import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; + import java.io.PrintWriter; /** @@ -44,6 +45,7 @@ public class SwipeSharedState implements SwipeAnimationListener { public boolean goingToLauncher; public boolean recentsAnimationFinishInterrupted; public int nextRunningTaskId = -1; + private int mLogId; public void setOverviewComponentObserver(OverviewComponentObserver observer) { mOverviewComponentObserver = observer; @@ -77,7 +79,7 @@ public class SwipeSharedState implements SwipeAnimationListener { mRecentsAnimationListener.removeListener(this); mRecentsAnimationListener.cancelListener(); if (mLastAnimationRunning && mLastAnimationTarget != null) { - Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), finishAnimation ? mLastAnimationTarget::finishAnimation : mLastAnimationTarget::cancelAnimation); @@ -155,5 +157,10 @@ public class SwipeSharedState implements SwipeAnimationListener { pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId); pw.println(prefix + "lastAnimationCancelled=" + mLastAnimationCancelled); pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning); + pw.println(prefix + "logTraceId=" + mLogId); + } + + public void setLogTraceId(int logId) { + this.mLogId = logId; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java index fd4592307..1af0db07d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java @@ -36,8 +36,6 @@ import android.view.View; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.ItemInfo; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; @@ -267,12 +265,16 @@ public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut @Override protected ActivityOptions makeLaunchOptions(Activity activity) { - return ActivityOptionsCompat.makeFreeformOptions(); + ActivityOptions activityOptions = ActivityOptionsCompat.makeFreeformOptions(); + // Arbitrary bounds only because freeform is in dev mode right now + Rect r = new Rect(50, 50, 200, 200); + activityOptions.setLaunchBounds(r); + return activityOptions; } @Override protected boolean onActivityStarted(BaseDraggingActivity activity) { - Launcher.getLauncher(activity).getStateManager().goToState(LauncherState.NORMAL); + activity.returnToHomescreen(); return true; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 86ba85578..729287c82 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -23,6 +23,8 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI; import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; @@ -50,8 +52,6 @@ import android.content.res.Configuration; import android.graphics.Point; import android.graphics.RectF; import android.graphics.Region; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.IBinder; @@ -61,18 +61,15 @@ import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.view.Choreographer; -import android.view.Display; import android.view.InputEvent; import android.view.MotionEvent; import android.view.Surface; -import android.view.WindowManager; import androidx.annotation.BinderThread; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; import com.android.launcher3.BaseDraggingActivity; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; import com.android.launcher3.Utilities; @@ -82,8 +79,7 @@ import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.util.LooperExecutor; -import com.android.launcher3.util.UiThreadHelper; +import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; @@ -106,8 +102,8 @@ import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import com.android.systemui.shared.system.RecentsAnimationListener; import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat; - import com.android.systemui.shared.system.TaskInfoCompat; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Arrays; @@ -136,11 +132,14 @@ class ArgList extends LinkedList<String> { */ @TargetApi(Build.VERSION_CODES.Q) public class TouchInteractionService extends Service implements - NavigationModeChangeListener, DisplayListener { + NavigationModeChangeListener, DefaultDisplay.DisplayInfoChangeListener { + + /** + * NOTE: This value should be kept same as + * ActivityTaskManagerService#INTENT_EXTRA_LOG_TRACE_ID in platform + */ + public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID"; - public static final MainThreadExecutor MAIN_THREAD_EXECUTOR = new MainThreadExecutor(); - public static final LooperExecutor BACKGROUND_EXECUTOR = - new LooperExecutor(UiThreadHelper.getBackgroundLooper()); public static final EventLogArray TOUCH_INTERACTION_LOG = new EventLogArray("touch_interaction_log", 40); @@ -161,9 +160,9 @@ public class TouchInteractionService extends Service implements public void onInitialize(Bundle bundle) { mISystemUiProxy = ISystemUiProxy.Stub .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); - MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); - MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet); - MAIN_THREAD_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */)); + MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); + MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet); + MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */)); sIsInitialized = true; } @@ -198,7 +197,7 @@ public class TouchInteractionService extends Service implements @Override public void onAssistantVisibilityChanged(float visibility) { mLastAssistantVisibility = visibility; - MAIN_THREAD_EXECUTOR.execute( + MAIN_EXECUTOR.execute( TouchInteractionService.this::onAssistantVisibilityChanged); } @@ -214,13 +213,13 @@ public class TouchInteractionService extends Service implements isButton, gestureSwipeLeft, activityControl.getContainerType()); if (completed && !isButton && shouldNotifyBackGesture()) { - BACKGROUND_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture); + UI_HELPER_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture); } } public void onSystemUiStateChanged(int stateFlags) { mSystemUiStateFlags = stateFlags; - MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); + MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); } /** Deprecated methods **/ @@ -244,6 +243,7 @@ public class TouchInteractionService extends Service implements private static boolean sConnected = false; private static boolean sIsInitialized = false; private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState(); + private int mLogId; public static boolean isConnected() { return sConnected; @@ -323,8 +323,7 @@ public class TouchInteractionService extends Service implements registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); } - mDefaultDisplayId = getSystemService(WindowManager.class).getDefaultDisplay() - .getDisplayId(); + mDefaultDisplayId = DefaultDisplay.INSTANCE.get(this).getInfo().id; String blockingActivity = getString(R.string.gesture_blocking_activity); mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null : ComponentName.unflattenFromString(blockingActivity); @@ -391,9 +390,8 @@ public class TouchInteractionService extends Service implements return; } - Display defaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay(); - Point realSize = new Point(); - defaultDisplay.getRealSize(realSize); + DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(this).getInfo(); + Point realSize = new Point(displayInfo.realSize); mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y); if (mMode == Mode.NO_BUTTON) { int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); @@ -415,7 +413,7 @@ public class TouchInteractionService extends Service implements } else { mAssistantLeftRegion.setEmpty(); mAssistantRightRegion.setEmpty(); - switch (defaultDisplay.getRotation()) { + switch (displayInfo.rotation) { case Surface.ROTATION_90: mSwipeTouchRegion.left = mSwipeTouchRegion.right - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE); @@ -438,10 +436,9 @@ public class TouchInteractionService extends Service implements } if (mMode.hasGestures != newMode.hasGestures) { if (newMode.hasGestures) { - getSystemService(DisplayManager.class).registerDisplayListener( - this, MAIN_THREAD_EXECUTOR.getHandler()); + DefaultDisplay.INSTANCE.get(this).addChangeListener(this); } else { - getSystemService(DisplayManager.class).unregisterDisplayListener(this); + DefaultDisplay.INSTANCE.get(this).removeChangeListener(this); } } mMode = newMode; @@ -457,14 +454,8 @@ public class TouchInteractionService extends Service implements } @Override - public void onDisplayAdded(int i) { } - - @Override - public void onDisplayRemoved(int i) { } - - @Override - public void onDisplayChanged(int displayId) { - if (displayId != mDefaultDisplayId) { + public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) { + if (info.id != mDefaultDisplayId) { return; } @@ -529,7 +520,7 @@ public class TouchInteractionService extends Service implements } disposeEventHandlers(); if (mMode.hasGestures) { - getSystemService(DisplayManager.class).unregisterDisplayListener(this); + DefaultDisplay.INSTANCE.get(this).removeChangeListener(this); } sConnected = false; @@ -554,9 +545,12 @@ public class TouchInteractionService extends Service implements Log.e(TAG, "Unknown event " + ev); return; } + MotionEvent event = (MotionEvent) ev; - TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked()); if (event.getAction() == ACTION_DOWN) { + mLogId = TOUCH_INTERACTION_LOG.generateAndSetLogId(); + sSwipeSharedState.setLogTraceId(mLogId); + if (mSwipeTouchRegion.contains(event.getX(), event.getY())) { boolean useSharedState = mConsumer.useSharedSwipeState(); mConsumer.onConsumerAboutToBeSwitched(); @@ -576,6 +570,8 @@ public class TouchInteractionService extends Service implements mUncheckedConsumer = InputConsumer.NO_OP; } } + + TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked()); mUncheckedConsumer.onMotionEvent(event); } @@ -661,7 +657,7 @@ public class TouchInteractionService extends Service implements final ComponentName homeComponent = mOverviewComponentObserver.getHomeIntent().getComponent(); forceOverviewInputConsumer = - runningTaskInfo.baseIntent.getComponent().equals(homeComponent); + runningTaskInfo.baseIntent.getComponent(). equals(homeComponent); } } @@ -718,13 +714,13 @@ public class TouchInteractionService extends Service implements return new OtherActivityInputConsumer(this, runningTaskInfo, shouldDefer, mOverviewCallbacks, this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, - disableHorizontalSwipe(event), factory); + disableHorizontalSwipe(event), factory, mLogId); } private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat, - mSwipeTouchRegion, taskInfo.taskId); + mSwipeTouchRegion, taskInfo.taskId, mLogId); } else { return mResetGestureInputConsumer; } @@ -788,7 +784,8 @@ public class TouchInteractionService extends Service implements } // Pass null animation handler to indicate this start is preload. - startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(), null); + startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(), + null); } @Override @@ -897,7 +894,7 @@ public class TouchInteractionService extends Service implements } public static void startRecentsActivityAsync(Intent intent, RecentsAnimationListener listener) { - BACKGROUND_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() + UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() .startRecentsActivity(intent, null, listener, null, null)); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index a3bd348e2..411a8088c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -479,8 +479,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask; if (animate) { // Only animate if an adjacent task view is visible on screen. - TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1); - TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1); + TaskView adjacentTask1 = mRecentsView.getNextTaskView(); + TaskView adjacentTask2 = mRecentsView.getPreviousTaskView(); float prevTranslationX = mRecentsView.getTranslationX(); mRecentsView.setTranslationX(0); animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT)) @@ -590,8 +590,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> */ private void updateSysUiFlags(float windowProgress) { if (mRecentsView != null) { - TaskView centermostTask = mRecentsView.getTaskViewAt(mRecentsView - .getPageNearestToCenterOfScreen()); + TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen(); int centermostTaskFlags = centermostTask == null ? 0 : centermostTask.getThumbnail().getSysUiStatusNavFlags(); boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java index 2e9c0a3c4..7f1aae5e2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -176,7 +176,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> { protected void applyLoadPlan(ArrayList<Task> tasks) { // When quick-switching on 3p-launcher, we add a "dummy" tile corresponding to Launcher // as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to - // track the index of the next task appropriately, as it we are switching on any other app. + // track the index of the next task appropriately, as if we are switching on any other app. if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) { // Check if the task list has running task boolean found = false; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 3d763ab52..b24c78810 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -22,8 +22,9 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; +import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; +import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; import android.content.ComponentName; import android.content.Context; @@ -35,10 +36,10 @@ import android.graphics.RectF; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; -import android.view.WindowManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.SwipeSharedState; @@ -76,6 +77,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final PointF mTouchDown = new PointF(); private final ClipAnimationHelper mClipAnimationHelper; + private int mLogId; private final ClipAnimationHelper.TransformParams mTransformParams; private final Point mDisplaySize; private final MultiStateCallback mStateCallback; @@ -90,19 +92,20 @@ public class DeviceLockedInputConsumer implements InputConsumer, private SwipeAnimationTargetSet mTargetSet; public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState, - InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId) { + InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId, + int logId) { mContext = context; mTouchSlopSquared = squaredTouchSlop(context); mSwipeSharedState = swipeSharedState; mClipAnimationHelper = new ClipAnimationHelper(context); + mLogId = logId; mTransformParams = new ClipAnimationHelper.TransformParams(); mInputMonitorCompat = inputMonitorCompat; mSwipeTouchRegion = swipeTouchRegion; mRunningTaskId = runningTaskId; // Do not use DeviceProfile as the user data might be locked - mDisplaySize = new Point(); - context.getSystemService(WindowManager.class).getDefaultDisplay().getRealSize(mDisplaySize); + mDisplaySize = DefaultDisplay.INSTANCE.get(context).getInfo().realSize; // Init states mStateCallback = new MultiStateCallback(STATE_NAMES); @@ -205,7 +208,8 @@ public class DeviceLockedInputConsumer implements InputConsumer, Intent intent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) + .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); mInputMonitorCompat.pilferPointers(); startRecentsActivityAsync(intent, newListenerSet); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 6ec1da0c4..e0ff8afe6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -50,7 +50,6 @@ import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.ObjectWrapper; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.SwipeAnimationTargetSet; -import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 86766d99f..e41880df5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -22,11 +22,11 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN; import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.INVALID_POINTER_ID; - import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; +import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -35,6 +35,7 @@ import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.ContextWrapper; +import android.content.Intent; import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; @@ -43,12 +44,13 @@ import android.os.Looper; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; - +import androidx.annotation.UiThread; import com.android.launcher3.R; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseSwipeUpHandler; +import com.android.quickstep.BaseSwipeUpHandler.Factory; import com.android.quickstep.OverviewCallbacks; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; @@ -59,11 +61,8 @@ import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.RecentsAnimationListenerSet; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; - import java.util.function.Consumer; -import androidx.annotation.UiThread; - /** * Input consumer for handling events originating from an activity other than Launcher */ @@ -119,14 +118,16 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC ActivityManagerWrapper.getInstance().cancelRecentsAnimation( true /* restoreHomeStackPosition */); }; + private int mLogId; public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks, Consumer<OtherActivityInputConsumer> onCompleteCallback, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, boolean disableHorizontalSwipe, - BaseSwipeUpHandler.Factory handlerFactory) { + Factory handlerFactory, int logId) { super(base); + mLogId = logId; mMainThreadHandler = new Handler(Looper.getMainLooper()); mRunningTask = runningTaskInfo; @@ -341,7 +342,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC RecentsAnimationListenerSet newListenerSet = mSwipeSharedState.newRecentsAnimationListenerSet(); newListenerSet.addListener(handler); - startRecentsActivityAsync(handler.getLaunchIntent(), newListenerSet); + Intent intent = handler.getLaunchIntent(); + intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); + startRecentsActivityAsync(intent, newListenerSet); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java index 3ce341d8c..bbb318a02 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java @@ -21,9 +21,9 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; import android.view.Surface; -import android.view.WindowManager; import com.android.launcher3.graphics.RotationMode; +import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.SysUINavigationMode; /** @@ -36,8 +36,7 @@ public class NavBarPosition { public NavBarPosition(Context context) { mMode = SysUINavigationMode.getMode(context); - mDisplayRotation = context.getSystemService(WindowManager.class) - .getDefaultDisplay().getRotation(); + mDisplayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation; } public boolean isRightEdge() { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java index 14083dd95..b1999d716 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java @@ -15,11 +15,13 @@ */ package com.android.quickstep.util; -import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.graphics.Rect; import android.util.ArraySet; +import androidx.annotation.UiThread; + import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; @@ -31,8 +33,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.Set; import java.util.function.Consumer; -import androidx.annotation.UiThread; - /** * Wrapper around {@link RecentsAnimationListener} which delegates callbacks to multiple listeners * on the main thread @@ -82,7 +82,7 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { if (mCancelled) { targetSet.cancelAnimation(); } else { - Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { for (SwipeAnimationListener listener : getListeners()) { listener.onRecentsAnimationStart(targetSet); } @@ -92,14 +92,14 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { @Override public final void onAnimationCanceled(ThumbnailData thumbnailData) { - Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { for (SwipeAnimationListener listener : getListeners()) { listener.onRecentsAnimationCanceled(); } }); // TODO: handle the transition better instead of simply using a transition delay. if (thumbnailData != null) { - MAIN_THREAD_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(), + MAIN_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(), TRANSITION_DELAY); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java index 381c27a28..3619d3a0e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java @@ -15,8 +15,8 @@ */ package com.android.quickstep.util; -import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR; -import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import android.graphics.Rect; @@ -68,25 +68,25 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) { mOnFinishListener.accept(this); - BACKGROUND_EXECUTOR.execute(() -> { + UI_HELPER_EXECUTOR.execute(() -> { controller.setInputConsumerEnabled(false); controller.finish(toRecents, sendUserLeaveHint); if (callback != null) { - MAIN_THREAD_EXECUTOR.execute(callback); + MAIN_EXECUTOR.execute(callback); } }); } public void enableInputConsumer() { - BACKGROUND_EXECUTOR.submit(() -> { + UI_HELPER_EXECUTOR.submit(() -> { controller.hideCurrentInputMethod(); controller.setInputConsumerEnabled(true); }); } public void setWindowThresholdCrossed(boolean thresholdCrossed) { - BACKGROUND_EXECUTOR.execute(() -> { + UI_HELPER_EXECUTOR.execute(() -> { controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed); if (mShouldMinimizeSplitScreen && thresholdCrossed) { // NOTE: As a workaround for conflicting animations (Launcher animating the task diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java index 7fac81385..b06d4bc35 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -19,6 +19,7 @@ package com.android.quickstep.views; import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS; import static com.android.launcher3.Utilities.prefixTextWithIcon; +import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; import android.annotation.TargetApi; import android.app.ActivityOptions; @@ -41,7 +42,6 @@ import androidx.annotation.StringRes; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.systemui.shared.recents.model.Task; @@ -117,7 +117,7 @@ public final class DigitalWellBeingToast { return; } - Utilities.THREAD_POOL_EXECUTOR.execute(() -> { + THREAD_POOL_EXECUTOR.execute(() -> { final AppUsageLimit usageLimit = mLauncherApps.getAppUsageLimit( task.getTopComponent().getPackageName(), UserHandle.of(task.key.userId)); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 03441c87e..b601834f3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -57,6 +57,8 @@ import com.android.quickstep.util.LayoutUtils; @TargetApi(Build.VERSION_CODES.O) public class LauncherRecentsView extends RecentsView<Launcher> implements StateListener { + private static final Rect sTempRect = new Rect(); + private final TransformParams mTransformParams = new TransformParams(); public LauncherRecentsView(Context context) { @@ -144,6 +146,25 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); } + /** + * @return The translationX to apply to this view so that the first task is just offscreen. + */ + public float getOffscreenTranslationX(float recentsScale) { + float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX; + // Offset since scale pushes tasks outwards. + getTaskSize(sTempRect); + int taskWidth = sTempRect.width(); + offscreenX += taskWidth * (recentsScale - 1) / 2; + if (mRunningTaskTileHidden) { + // The first task is hidden, so offset by its width. + offscreenX -= (taskWidth + getPageSpacing()) * recentsScale; + } + if (isRtl()) { + offscreenX = -offscreenX; + } + return offscreenX; + } + @Override protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index d98ef425e..554f4372c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -35,9 +35,9 @@ import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS; import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; -import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR; import android.animation.Animator; import android.animation.AnimatorSet; @@ -228,7 +228,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl return; } - BACKGROUND_EXECUTOR.execute(() -> { + UI_HELPER_EXECUTOR.execute(() -> { TaskView taskView = getTaskView(taskId); if (taskView == null) { return; @@ -272,7 +272,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl // Only valid until the launcher state changes to NORMAL protected int mRunningTaskId = -1; - private boolean mRunningTaskTileHidden; + protected boolean mRunningTaskTileHidden; private Task mTmpRunningTask; private boolean mRunningTaskIconScaledDown = false; @@ -306,6 +306,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl private Layout mEmptyTextLayout; private LiveTileOverlay mLiveTileOverlay; + // Keeps track of the index where the first TaskView should be + private int mTaskViewStartIndex = 0; + private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener = (inMultiWindowMode) -> { if (!inMultiWindowMode && mOverviewStateEnabled) { @@ -329,7 +332,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl mClearAllButton = (ClearAllButton) LayoutInflater.from(context) .inflate(R.layout.overview_clear_all_button, this, false); mClearAllButton.setOnClickListener(this::dismissAllTasks); - mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */, 10 /* initial size */); @@ -430,7 +432,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl super.onViewRemoved(child); // Clear the task data for the removed child if it was visible - if (child != mClearAllButton) { + if (child instanceof TaskView) { TaskView taskView = (TaskView) child; mHasVisibleTaskData.delete(taskView.getTask().key.id); mTaskViewPool.recycle(taskView); @@ -444,7 +446,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl public TaskView getTaskView(int taskId) { for (int i = 0; i < getTaskViewCount(); i++) { - TaskView tv = (TaskView) getChildAt(i); + TaskView tv = getTaskViewAt(i); if (tv.getTask() != null && tv.getTask().key != null && tv.getTask().key.id == taskId) { return tv; } @@ -536,28 +538,26 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl } if (tasks == null || tasks.isEmpty()) { - removeAllViews(); + removeTasksViewsAndClearAllButton(); onTaskStackUpdated(); return; } - int oldChildCount = getChildCount(); - // Unload existing visible task data unloadVisibleTaskData(); - TaskView ignoreRestTaskView = + TaskView ignoreResetTaskView = mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId); final int requiredTaskCount = tasks.size(); if (getTaskViewCount() != requiredTaskCount) { - if (oldChildCount > 0) { + if (indexOfChild(mClearAllButton) != -1) { removeView(mClearAllButton); } - for (int i = getChildCount(); i < requiredTaskCount; i++) { + for (int i = getTaskViewCount(); i < requiredTaskCount; i++) { addView(mTaskViewPool.getView()); } - while (getChildCount() > requiredTaskCount) { + while (getTaskViewCount() > requiredTaskCount) { removeView(getChildAt(getChildCount() - 1)); } if (requiredTaskCount > 0) { @@ -567,17 +567,20 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl // Rebind and reset all task views for (int i = requiredTaskCount - 1; i >= 0; i--) { - final int pageIndex = requiredTaskCount - i - 1; + final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex; final Task task = tasks.get(i); final TaskView taskView = (TaskView) getChildAt(pageIndex); taskView.bind(task); } + TaskView runningTaskView = getRunningTaskView(); if (runningTaskView != null) { setCurrentPage(indexOfChild(runningTaskView)); + } else if (getTaskViewCount() > 0) { + setCurrentPage(indexOfChild(getTaskViewAt(0))); } - if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) { + if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) { // If the taskView mapping is changing, do not preserve the visuals. Since we are // mostly preserving the first task, and new taskViews are added to the end, it should // generally map to the same task. @@ -588,17 +591,28 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl updateEnabledOverlays(); } + private void removeTasksViewsAndClearAllButton() { + for (int i = getTaskViewCount() - 1; i >= 0; i--) { + removeView(getTaskViewAt(i)); + } + if (indexOfChild(mClearAllButton) != -1) { + removeView(mClearAllButton); + } + } + public int getTaskViewCount() { - // Account for the clear all button. - int childCount = getChildCount(); - return childCount == 0 ? 0 : childCount - 1; + int taskViewCount = getChildCount() - mTaskViewStartIndex; + if (indexOfChild(mClearAllButton) != -1) { + taskViewCount--; + } + return taskViewCount; } protected void onTaskStackUpdated() { } public void resetTaskVisuals() { for (int i = getTaskViewCount() - 1; i >= 0; i--) { - TaskView taskView = (TaskView) getChildAt(i); + TaskView taskView = getTaskViewAt(i); if (mIgnoreResetTaskId != taskView.getTask().key.id) { taskView.resetVisualProperties(); taskView.setStableAlpha(mContentAlpha); @@ -704,7 +718,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl } /** - * Iterates through all thet asks, and loads the associated task data for newly visible tasks, + * Iterates through all the tasks, and loads the associated task data for newly visible tasks, * and unloads the associated task data for tasks that are no longer visible. */ public void loadVisibleTaskData() { @@ -715,15 +729,16 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl } int centerPageIndex = getPageNearestToCenterOfScreen(); - int numChildren = getTaskViewCount(); + int numChildren = getChildCount(); int lower = Math.max(0, centerPageIndex - 2); int upper = Math.min(centerPageIndex + 2, numChildren - 1); // Update the task data for the in/visible children - for (int i = 0; i < numChildren; i++) { - TaskView taskView = (TaskView) getChildAt(i); + for (int i = 0; i < getTaskViewCount(); i++) { + TaskView taskView = getTaskViewAt(i); Task task = taskView.getTask(); - boolean visible = lower <= i && i <= upper; + int index = indexOfChild(taskView); + boolean visible = lower <= index && index <= upper; if (visible) { if (task == mTmpRunningTask) { // Skip loading if this is the task that we are animating into @@ -798,6 +813,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl return tv == null ? -1 : indexOfChild(tv); } + public int getTaskViewStartIndex() { + return mTaskViewStartIndex; + } + /** * Reloads the view if anything in recents changed. */ @@ -853,10 +872,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl */ public void showCurrentTask(int runningTaskId) { if (getTaskView(runningTaskId) == null) { - boolean wasEmpty = getChildCount() == 0; + boolean wasEmpty = getTaskViewCount() == 0; // Add an empty view for now until the task plan is loaded and applied final TaskView taskView = mTaskViewPool.getView(); - addView(taskView, 0); + addView(taskView, mTaskViewStartIndex); if (wasEmpty) { addView(mClearAllButton); } @@ -922,14 +941,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl if (runningTaskView == null) { // Launch the first task if (getTaskViewCount() > 0) { - getTaskViewAt(0).launchTask(true /* animate */); + getTaskViewAt(0).launchTask(true); } } else { - TaskView nextTaskView = getNextTaskView(); - if (nextTaskView != null) { - nextTaskView.launchTask(true /* animate */); + if (getNextTaskView() != null) { + getNextTaskView().launchTask(true); } else { - runningTaskView.launchTask(true /* animate */); + runningTaskView.launchTask(true); } } } @@ -1193,7 +1211,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl int count = getTaskViewCount(); for (int i = 0; i < count; i++) { - addDismissedTaskAnimations(getChildAt(i), anim, duration); + addDismissedTaskAnimations(getTaskViewAt(i), anim, duration); } mPendingAnimation = pendingAnimation; @@ -1201,7 +1219,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl if (onEndListener.isSuccess) { // Remove all the task views now ActivityManagerWrapper.getInstance().removeAllRecentTasks(); - removeAllViews(); + removeTasksViewsAndClearAllButton(); startHome(); } mPendingAnimation = null; @@ -1348,26 +1366,50 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl child.setAlpha(mContentAlpha); } - /** - * @return The most recent task that is older than the currently running task. If there is - * currently no running task or there is no task older than it, then return null. - */ @Nullable public TaskView getNextTaskView() { - TaskView runningTaskView = getRunningTaskView(); - if (runningTaskView == null) { - return null; - } - return getTaskViewAt(indexOfChild(runningTaskView) + 1); + return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1); } + @Nullable + public TaskView getPreviousTaskView() { + return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1); + } + + @Nullable + public TaskView getCurrentPageTaskView() { + return getTaskViewAtByAbsoluteIndex(getCurrentPage()); + } + + @Nullable + public TaskView getNextPageTaskView() { + return getTaskViewAtByAbsoluteIndex(getNextPage()); + } + + @Nullable + public TaskView getTaskViewNearestToCenterOfScreen() { + return getTaskViewAtByAbsoluteIndex(getPageNearestToCenterOfScreen()); + } + + /** + * Returns null instead of indexOutOfBoundsError when index is not in range + */ + @Nullable public TaskView getTaskViewAt(int index) { - View child = getChildAt(index); - return child == mClearAllButton ? null : (TaskView) child; + return getTaskViewAtByAbsoluteIndex(index + mTaskViewStartIndex); + } + + @Nullable + private TaskView getTaskViewAtByAbsoluteIndex(int index) { + if (index < getChildCount() && index >= 0) { + View child = getChildAt(index); + return child instanceof TaskView ? (TaskView) child : null; + } + return null; } public void updateEmptyMessage() { - boolean isEmpty = getChildCount() == 0; + boolean isEmpty = getTaskViewCount() == 0; boolean hasSizeChanged = mLastMeasureSize.x != getWidth() || mLastMeasureSize.y != getHeight(); if (isEmpty == mShowEmptyMessage && !hasSizeChanged) { @@ -1501,7 +1543,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl throw new IllegalStateException("Another pending animation is still running"); } - int count = getChildCount(); + int count = getTaskViewCount(); if (count == 0) { return new PendingAnimation(new AnimatorSet()); } @@ -1674,18 +1716,38 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl @Override protected int computeMinScrollX() { - if (mIsRtl && mDisallowScrollToClearAll) { - // We aren't showing the clear all button, so use the leftmost task as the min scroll. - return getScrollForPage(getTaskViewCount() - 1); + if (getTaskViewCount() > 0) { + if (mDisallowScrollToClearAll) { + // We aren't showing the clear all button, + // so use the leftmost task as the min scroll. + if (mIsRtl) { + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); + } + return getScrollForPage(mTaskViewStartIndex); + } + if (mIsRtl) { + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); + } + return getScrollForPage(mTaskViewStartIndex); } return super.computeMinScrollX(); } @Override protected int computeMaxScrollX() { - if (!mIsRtl && mDisallowScrollToClearAll) { - // We aren't showing the clear all button, so use the rightmost task as the max scroll. - return getScrollForPage(getTaskViewCount() - 1); + if (getTaskViewCount() > 0) { + if (mDisallowScrollToClearAll) { + // We aren't showing the clear all button, + // so use the rightmost task as the min scroll. + if (mIsRtl) { + return getScrollForPage(mTaskViewStartIndex); + } + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1))); + } + if (mIsRtl) { + return getScrollForPage(mTaskViewStartIndex); + } + return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1); } return super.computeMaxScrollX(); } @@ -1737,7 +1799,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1; int taskCount = getTaskViewCount(); for (int i = 0; i < taskCount; i++) { - ((TaskView) getChildAt(i)).setOverlayEnabled(i == overlayEnabledPage); + getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java index 910fa0df6..7beb9db84 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java +++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java @@ -14,16 +14,17 @@ package com.android.launcher3.uioverrides.plugins; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + import android.content.Context; import android.os.Looper; -import com.android.launcher3.LauncherModel; import com.android.systemui.shared.plugins.PluginInitializer; public class PluginInitializerImpl implements PluginInitializer { @Override public Looper getBgLooper() { - return LauncherModel.getWorkerLooper(); + return MODEL_EXECUTOR.getLooper(); } @Override diff --git a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java b/quickstep/src/com/android/quickstep/BaseRecentsActivity.java index c84013257..1ac7ed4a3 100644 --- a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java +++ b/quickstep/src/com/android/quickstep/BaseRecentsActivity.java @@ -157,6 +157,6 @@ public abstract class BaseRecentsActivity extends BaseDraggingActivity { public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { super.dump(prefix, fd, writer, args); writer.println(prefix + "Misc:"); - dumpMisc(writer); + dumpMisc(prefix + "\t", writer); } } diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java index 78b48d77a..858c3b6b3 100644 --- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java +++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java @@ -15,20 +15,21 @@ */ package com.android.quickstep; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; + import android.content.Context; import android.os.Handler; import android.os.Message; import android.os.RemoteException; import android.util.Log; +import androidx.annotation.WorkerThread; + import com.android.launcher3.Utilities; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.launcher3.util.UiThreadHelper; import com.android.systemui.shared.recents.ISystemUiProxy; -import androidx.annotation.WorkerThread; - /** * Sets alpha for the back button */ @@ -62,7 +63,7 @@ public class OverviewInteractionState { // because of its high send frequency and data may be very different than the previous value // For example, send back alpha on uihandler to avoid flickering when setting its visibility mUiHandler = new Handler(this::handleUiMessage); - mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage); + mBgHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleBgMessage); onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context) .addModeChangeListener(this::onNavigationModeChanged)); diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index e41dba94c..10f9febfb 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -16,19 +16,22 @@ package com.android.quickstep; -import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.annotation.TargetApi; import android.app.ActivityManager; -import android.content.Context; import android.os.Build; import android.os.Process; import android.util.SparseBooleanArray; -import com.android.launcher3.MainThreadExecutor; + +import androidx.annotation.VisibleForTesting; + +import com.android.launcher3.util.LooperExecutor; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.KeyguardManagerCompat; import com.android.systemui.shared.system.TaskStackChangeListener; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -41,7 +44,8 @@ import java.util.function.Consumer; public class RecentTasksList extends TaskStackChangeListener { private final KeyguardManagerCompat mKeyguardManager; - private final MainThreadExecutor mMainThreadExecutor; + private final LooperExecutor mMainThreadExecutor; + private final ActivityManagerWrapper mActivityManagerWrapper; // The list change id, increments as the task list changes in the system private int mChangeId; @@ -52,11 +56,13 @@ public class RecentTasksList extends TaskStackChangeListener { ArrayList<Task> mTasks = new ArrayList<>(); - public RecentTasksList(Context context) { - mMainThreadExecutor = new MainThreadExecutor(); - mKeyguardManager = new KeyguardManagerCompat(context); + public RecentTasksList(LooperExecutor mainThreadExecutor, + KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) { + mMainThreadExecutor = mainThreadExecutor; + mKeyguardManager = keyguardManager; mChangeId = 1; - ActivityManagerWrapper.getInstance().registerTaskStackListener(this); + mActivityManagerWrapper = activityManagerWrapper; + mActivityManagerWrapper.registerTaskStackListener(this); } /** @@ -64,7 +70,7 @@ public class RecentTasksList extends TaskStackChangeListener { */ public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) { // Kick off task loading in the background - BACKGROUND_EXECUTOR.execute(() -> { + UI_HELPER_EXECUTOR.execute(() -> { ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */); mMainThreadExecutor.execute(() -> callback.accept(tasks)); }); @@ -86,12 +92,12 @@ public class RecentTasksList extends TaskStackChangeListener { if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) { // The list is up to date, send the callback on the next frame, // so that requestID can be returned first. - mMainThreadExecutor.getHandler().post(resultCallback); + mMainThreadExecutor.post(resultCallback); return requestLoadId; } // Kick off task loading in the background - BACKGROUND_EXECUTOR.execute(() -> { + UI_HELPER_EXECUTOR.execute(() -> { ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly); mMainThreadExecutor.execute(() -> { @@ -136,12 +142,13 @@ public class RecentTasksList extends TaskStackChangeListener { /** * Loads and creates a list of all the recent tasks. */ - private ArrayList<Task> loadTasksInBackground(int numTasks, + @VisibleForTesting + ArrayList<Task> loadTasksInBackground(int numTasks, boolean loadKeysOnly) { int currentUserId = Process.myUserHandle().getIdentifier(); ArrayList<Task> allTasks = new ArrayList<>(); List<ActivityManager.RecentTaskInfo> rawTasks = - ActivityManagerWrapper.getInstance().getRecentTasks(numTasks, currentUserId); + mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId); // The raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(rawTasks); diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java index f9d2f11cb..4d1d9ef8a 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java +++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java @@ -15,6 +15,8 @@ */ package com.android.quickstep; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; @@ -22,7 +24,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; -import com.android.launcher3.MainThreadExecutor; import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationProvider; @@ -92,14 +93,10 @@ public class RecentsActivityTracker<T extends BaseRecentsActivity> implements Ac private static class Scheduler implements Runnable { private WeakReference<RecentsActivityTracker> mPendingTracker = new WeakReference<>(null); - private MainThreadExecutor mMainThreadExecutor; public synchronized void schedule(RecentsActivityTracker tracker) { mPendingTracker = new WeakReference<>(tracker); - if (mMainThreadExecutor == null) { - mMainThreadExecutor = new MainThreadExecutor(); - } - mMainThreadExecutor.execute(this); + MAIN_EXECUTOR.execute(this); } @Override diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index dfab43459..2e59ed5e4 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -15,6 +15,10 @@ */ 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; @@ -22,16 +26,20 @@ import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Build; -import android.os.HandlerThread; +import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.KeyguardManagerCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; @@ -61,13 +69,14 @@ public class RecentsModel extends TaskStackChangeListener { private RecentsModel(Context context) { mContext = context; - HandlerThread loaderThread = new HandlerThread("TaskThumbnailIconCache", - Process.THREAD_PRIORITY_BACKGROUND); - loaderThread.start(); - mTaskList = new RecentTasksList(context); - mIconCache = new TaskIconCache(context, loaderThread.getLooper()); - mThumbnailCache = new TaskThumbnailCache(context, loaderThread.getLooper()); + 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); ActivityManagerWrapper.getInstance().registerTaskStackListener(this); + setupPackageListener(); } public TaskIconCache getIconCache() { @@ -166,6 +175,7 @@ public class RecentsModel extends TaskStackChangeListener { public void onTaskRemoved(int taskId) { Task.TaskKey dummyKey = new Task.TaskKey(taskId, 0, null, null, 0, 0); mThumbnailCache.remove(dummyKey); + mIconCache.onTaskRemoved(dummyKey); } public void setSystemUiProxy(ISystemUiProxy systemUiProxy) { @@ -200,6 +210,21 @@ public class RecentsModel extends TaskStackChangeListener { } } + private void setupPackageListener() { + LauncherAppsCompat.getInstance(mContext) + .addOnAppsChangedCallback(new OnAppsChangedCallbackCompat() { + @Override + public void onPackageRemoved(String packageName, UserHandle user) { + mIconCache.invalidatePackage(packageName); + } + + @Override + public void onPackageChanged(String packageName, UserHandle user) { + mIconCache.invalidatePackage(packageName); + } + }); + } + public void addThumbnailChangeListener(TaskThumbnailChangeListener listener) { mThumbnailChangeListeners.add(listener); } diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index 07af9b385..289a12970 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -16,6 +16,7 @@ package com.android.quickstep; import static com.android.launcher3.uioverrides.RecentsUiFactory.GO_LOW_RAM_RECENTS_ENABLED; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.ComponentName; import android.content.Context; @@ -27,26 +28,25 @@ import android.os.Looper; import android.util.LruCache; import android.view.accessibility.AccessibilityManager; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.icons.cache.HandlerRunnable; -import com.android.launcher3.uioverrides.RecentsUiFactory; import com.android.launcher3.util.Preconditions; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.TaskKeyLruCache; import com.android.systemui.shared.system.ActivityManagerWrapper; +import java.util.Map; import java.util.function.Consumer; /** * Manages the caching of task icons and related data. - * TODO: This class should later be merged into IconCache. + * TODO(b/138944598): This class should later be merged into IconCache. */ public class TaskIconCache { private final Handler mBackgroundHandler; - private final MainThreadExecutor mMainThreadExecutor; private final AccessibilityManager mAccessibilityManager; private final NormalizedIconLoader mIconLoader; @@ -67,7 +67,6 @@ public class TaskIconCache { public TaskIconCache(Context context, Looper backgroundLooper) { mBackgroundHandler = new Handler(backgroundLooper); - mMainThreadExecutor = new MainThreadExecutor(); mAccessibilityManager = context.getSystemService(AccessibilityManager.class); Resources res = context.getResources(); @@ -103,7 +102,7 @@ public class TaskIconCache { // We don't call back to the provided callback in this case return; } - mMainThreadExecutor.execute(() -> { + MAIN_EXECUTOR.execute(() -> { task.icon = icon; task.titleDescription = contentDescription; callback.accept(task); @@ -149,6 +148,21 @@ public class TaskIconCache { return label; } + + void onTaskRemoved(TaskKey taskKey) { + mIconCache.remove(taskKey); + } + + void invalidatePackage(String packageName) { + // TODO(b/138944598): Merge this class into IconCache so we can do this at the base level + Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot(); + for (ComponentName cn : activityInfoCache.keySet()) { + if (cn.getPackageName().equals(packageName)) { + mActivityInfoCache.remove(cn); + } + } + } + public static abstract class IconLoadRequest extends HandlerRunnable { IconLoadRequest(Handler handler) { super(handler, null); diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java index 57c5a2783..3b50c2623 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java @@ -15,12 +15,14 @@ */ package com.android.quickstep; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; import android.os.Handler; import android.os.Looper; -import com.android.launcher3.MainThreadExecutor; + import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.icons.cache.HandlerRunnable; @@ -30,13 +32,13 @@ import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.TaskKeyLruCache; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; + import java.util.ArrayList; import java.util.function.Consumer; public class TaskThumbnailCache { private final Handler mBackgroundHandler; - private final MainThreadExecutor mMainThreadExecutor; private final int mCacheSize; private final ThumbnailCache mCache; @@ -94,7 +96,6 @@ public class TaskThumbnailCache { public TaskThumbnailCache(Context context, Looper backgroundLooper) { mBackgroundHandler = new Handler(backgroundLooper); - mMainThreadExecutor = new MainThreadExecutor(); mHighResLoadingState = new HighResLoadingState(context); Resources res = context.getResources(); @@ -168,7 +169,7 @@ public class TaskThumbnailCache { // We don't call back to the provided callback in this case return; } - mMainThreadExecutor.execute(() -> { + MAIN_EXECUTOR.execute(() -> { mCache.put(key, thumbnail); callback.accept(thumbnail); onEnd(); diff --git a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java index d0956d1f6..7801775d4 100644 --- a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java +++ b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java @@ -150,10 +150,10 @@ public class AppPredictionsUITests extends AbstractQuickStepTest { List<AppTarget> targets = new ArrayList<>(activities.length); for (LauncherActivityInfo info : activities) { ComponentName cn = info.getComponentName(); - AppTarget target = - new AppTarget.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser()) - .setClassName(cn.getClassName()) - .build(); + AppTarget target = new AppTarget.Builder( + new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser()) + .setClassName(cn.getClassName()) + .build(); targets.add(target); } mCallback.onTargetsAvailable(targets); diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java new file mode 100644 index 000000000..34eb7f817 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java @@ -0,0 +1,99 @@ +/* + * 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.quickstep; + +import static junit.framework.TestCase.assertNull; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; + +import androidx.test.filters.SmallTest; + +import com.android.launcher3.util.LooperExecutor; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.KeyguardManagerCompat; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +@SmallTest +public class RecentTasksListTest { + + private ActivityManagerWrapper mockActivityManagerWrapper; + + // Class under test + private RecentTasksList mRecentTasksList; + + @Before + public void setup() { + LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class); + KeyguardManagerCompat mockKeyguardManagerCompat = mock(KeyguardManagerCompat.class); + mockActivityManagerWrapper = mock(ActivityManagerWrapper.class); + mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManagerCompat, + mockActivityManagerWrapper); + } + + @Test + public void onTaskRemoved_reloadsAllTasks() { + mRecentTasksList.onTaskRemoved(0); + verify(mockActivityManagerWrapper, times(1)) + .getRecentTasks(anyInt(), anyInt()); + } + + @Test + public void onTaskStackChanged_doesNotFetchTasks() { + mRecentTasksList.onTaskStackChanged(); + verify(mockActivityManagerWrapper, times(0)) + .getRecentTasks(anyInt(), anyInt()); + } + + @Test + public void loadTasksInBackground_onlyKeys_noValidTaskDescription() { + ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo(); + when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt())) + .thenReturn(Collections.singletonList(recentTaskInfo)); + + List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true); + + assertEquals(1, taskList.size()); + assertNull(taskList.get(0).taskDescription.getLabel()); + } + + @Test + public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() { + String taskDescription = "Wheeee!"; + ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo(); + recentTaskInfo.taskDescription = new ActivityManager.TaskDescription(taskDescription); + when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt())) + .thenReturn(Collections.singletonList(recentTaskInfo)); + + List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false); + + assertEquals(1, taskList.size()); + assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel()); + } +} |