Merge "[-1] Fix flicker of -1 when swipe up to exit -1 isn't fast enough" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index bc49146..f0a9cba 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -543,4 +543,14 @@
namespace: "launcher"
description: "Enable launcher icon shape customizations"
bug: "348708061"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "predictive_back_to_home_polish"
+ namespace: "launcher"
+ description: "Enables workspace reveal animation for predictive back-to-home"
+ bug: "382453424"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index e8c8505..1f33e08 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -23,7 +23,6 @@
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
- <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
<string name="widget_holder_factory_class" translatable="false">com.android.launcher3.uioverrides.QuickstepWidgetHolder$QuickstepHolderFactory</string>
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
<string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
index 1161720..08ef8fe 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3;
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
+
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
import android.view.KeyEvent;
@@ -48,7 +50,11 @@
public void onPopulateAccessibilityEvent(View view, AccessibilityEvent event) {
super.onPopulateAccessibilityEvent(view, event);
// Scroll to the position if focused view in main allapps list and not completely visible.
- scrollToPositionIfNeeded(view);
+ // Gate based on TYPE_VIEW_ACCESSIBILITY_FOCUSED for unintended scrolling with external
+ // mouse.
+ if (event.getEventType() == TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
+ scrollToPositionIfNeeded(view);
+ }
}
private void scrollToPositionIfNeeded(View view) {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2759816..f38693d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1670,7 +1670,10 @@
|| mLauncher.getWorkspace().isOverlayShown()
|| shouldPlayFallbackClosingAnimation(appTargets);
- boolean playWorkspaceReveal = !fromPredictiveBack;
+ boolean playWorkspaceReveal = true;
+ if (!Flags.predictiveBackToHomePolish()) {
+ playWorkspaceReveal = !fromPredictiveBack;
+ }
boolean skipAllAppsScale = false;
if (!playFallBackAnimation) {
PointF velocity;
@@ -1689,12 +1692,12 @@
// Skip scaling all apps, otherwise FloatingIconView will get wrong
// layout bounds.
skipAllAppsScale = true;
- } else if (!fromPredictiveBack) {
+ } else if (Flags.predictiveBackToHomePolish() || !fromPredictiveBack) {
if (enableScalingRevealHomeAnimation()) {
anim.play(
- new ScalingWorkspaceRevealAnim(
- mLauncher, rectFSpringAnim,
- rectFSpringAnim.getTargetRect()).getAnimators());
+ new ScalingWorkspaceRevealAnim(mLauncher, rectFSpringAnim,
+ rectFSpringAnim.getTargetRect(),
+ !fromPredictiveBack /* playAlphaReveal */).getAnimators());
} else {
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
true /* animateOverviewScrim */, launcherView).getAnimators());
@@ -1713,15 +1716,7 @@
anim.play(getFallbackClosingWindowAnimators(appTargets));
}
- // Normally, we run the launcher content animation when we are transitioning
- // home, but if home is already visible, then we don't want to animate the
- // contents of launcher unless we know that we are animating home as a result
- // of the home button press with quickstep, which will result in launcher being
- // started on touch down, prior to the animation home (and won't be in the
- // targets list because it is already visible). In that case, we force
- // invisibility on touch down, and only reset it after the animation to home
- // is initialized.
- if (launcherIsForceInvisibleOrOpening || fromPredictiveBack) {
+ if (Flags.predictiveBackToHomePolish()) {
AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -1730,7 +1725,24 @@
mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
}
};
+ if (rectFSpringAnim != null) {
+ rectFSpringAnim.addAnimatorListener(endListener);
+ } else {
+ anim.addListener(endListener);
+ }
+ }
+ // Normally, we run the launcher content animation when we are transitioning
+ // home, but if home is already visible, then we don't want to animate the
+ // contents of launcher unless we know that we are animating home as a result
+ // of the home button press with quickstep, which will result in launcher being
+ // started on touch down, prior to the animation home (and won't be in the
+ // targets list because it is already visible). In that case, we force
+ // invisibility on touch down, and only reset it after the animation to home
+ // is initialized.
+ boolean legacyFromPredictiveBack =
+ !Flags.predictiveBackToHomePolish() && fromPredictiveBack;
+ if (launcherIsForceInvisibleOrOpening || legacyFromPredictiveBack) {
if (rectFSpringAnim != null && anim.getChildAnimations().isEmpty()) {
addCujInstrumentation(rectFSpringAnim, Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
} else {
@@ -1738,17 +1750,26 @@
? Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK
: Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
}
-
- if (fromPredictiveBack && rectFSpringAnim != null) {
- rectFSpringAnim.addAnimatorListener(endListener);
- } else {
- anim.addListener(endListener);
+ if (!Flags.predictiveBackToHomePolish()) {
+ AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ AccessibilityManagerCompat.sendTestProtocolEventToTest(
+ mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
+ }
+ };
+ if (fromPredictiveBack && rectFSpringAnim != null) {
+ rectFSpringAnim.addAnimatorListener(endListener);
+ } else {
+ anim.addListener(endListener);
+ }
}
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
- if (mLauncher.isInState(LauncherState.ALL_APPS) && !fromPredictiveBack) {
+ if (mLauncher.isInState(LauncherState.ALL_APPS) && !legacyFromPredictiveBack) {
Pair<AnimatorSet, Runnable> contentAnimator =
getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
skipAllAppsScale);
diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
index d604742..cd08897 100644
--- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.EncryptionType.ENCRYPTED;
import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
import android.app.prediction.AppTarget;
@@ -95,7 +96,7 @@
itemInfo = apps.data.stream()
.filter(info -> user.equals(info.user) && cn.equals(info.componentName))
.map(ai -> {
- app.getIconCache().getTitleAndIcon(ai, false);
+ app.getIconCache().getTitleAndIcon(ai, DEFAULT_LOOKUP_FLAG);
return ai.makeWorkspaceItem(context);
})
.findAny()
@@ -106,7 +107,7 @@
return null;
}
AppInfo ai = new AppInfo(context, lai, user);
- app.getIconCache().getTitleAndIcon(ai, lai, false);
+ app.getIconCache().getTitleAndIcon(ai, lai, DEFAULT_LOOKUP_FLAG);
return ai.makeWorkspaceItem(context);
});
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 2f4c6f6..daba0dd 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -572,7 +573,7 @@
mPmHelper,
mUMS.isUserQuiet(user));
info.container = mContainer;
- mAppState.getIconCache().getTitleAndIcon(info, lai, false);
+ mAppState.getIconCache().getTitleAndIcon(info, lai, DEFAULT_LOOKUP_FLAG);
mReadCount++;
return info.makeWorkspaceItem(mAppState.getContext());
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 7d75286..ea42d77 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -217,8 +217,10 @@
private int getTaskbarAnimationDuration(boolean isVisible) {
// fast animation duration since we will not be playing workspace reveal animation.
- boolean shouldOverrideToFastAnimation =
- !isHotseatIconOnTopWhenAligned() || mLauncher.getPredictiveBackToHomeInProgress();
+ boolean shouldOverrideToFastAnimation = !isHotseatIconOnTopWhenAligned();
+ if (!Flags.predictiveBackToHomePolish()) {
+ shouldOverrideToFastAnimation |= mLauncher.getPredictiveBackToHomeInProgress();
+ }
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mLauncher);
if (isVisible || isPinnedTaskbar) {
return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index dddfdfe..c7ef960 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -25,6 +25,7 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
@@ -230,15 +231,19 @@
@Override
public void onLongPress(@NonNull MotionEvent event) {
- maybeShowPinningView(event);
+ if (maybeShowPinningView(event)) {
+ mTaskbarView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
}
- private void maybeShowPinningView(@NonNull MotionEvent event) {
+ /** Returns true if the taskbar pinning popup view was shown for {@code event}. */
+ private boolean maybeShowPinningView(@NonNull MotionEvent event) {
if (!DisplayController.isPinnedTaskbar(mActivity) || mTaskbarView.isEventOverAnyItem(
event)) {
- return;
+ return false;
}
mControllers.taskbarPinningController.showPinningView(mTaskbarView, event.getRawX());
+ return true;
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 3065d48..9683f8b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -442,10 +442,11 @@
}
}
- // Update the visibility if this is the initial state or if there are no bubbles.
+ // Update the visibility if this is the initial state, if there are no bubbles, or if the
+ // animation is suppressed.
// If this is the initial bubble, the bubble bar will become visible as part of the
// animation.
- if (update.initialState || mBubbles.isEmpty()) {
+ if (update.initialState || mBubbles.isEmpty() || suppressAnimation) {
mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
}
mBubbleStashedHandleViewController.ifPresent(
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 4bd9ffb..69f28fa 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -51,11 +51,15 @@
import android.window.BackProgressAnimator;
import android.window.IBackAnimationHandoffHandler;
import android.window.IOnBackInvokedCallback;
+
+import com.android.app.animation.Animations;
import com.android.app.animation.Interpolators;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -65,6 +69,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.quickstep.util.BackAnimState;
+import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.systemui.shared.system.QuickStepContract;
import java.lang.ref.WeakReference;
@@ -87,7 +92,8 @@
*/
public class LauncherBackAnimationController {
private static final int SCRIM_FADE_DURATION = 233;
- private static final float MIN_WINDOW_SCALE = 0.85f;
+ private static final float MIN_WINDOW_SCALE =
+ Flags.predictiveBackToHomePolish() ? 0.75f : 0.85f;
private static final float MAX_SCRIM_ALPHA_DARK = 0.8f;
private static final float MAX_SCRIM_ALPHA_LIGHT = 0.2f;
@@ -314,6 +320,14 @@
new RemoteAnimationTarget[]{ mBackTarget });
setLauncherTargetViewVisible(false);
mCurrentRect.set(mStartRect);
+ if (Flags.predictiveBackToHomePolish() && !mLauncher.getWorkspace().isOverlayShown()
+ && !mLauncher.isInState(LauncherState.ALL_APPS)) {
+ Animations.cancelOngoingAnimation(mLauncher.getWorkspace());
+ Animations.cancelOngoingAnimation(mLauncher.getHotseat());
+ mLauncher.getDepthController().stateDepth.setValue(
+ LauncherState.BACKGROUND_APP.getDepth(mLauncher));
+ setLauncherScale(ScalingWorkspaceRevealAnim.MIN_SIZE);
+ }
if (mScrimLayer == null) {
addScrimLayer();
}
@@ -328,6 +342,13 @@
}
}
+ private void setLauncherScale(float scale) {
+ mLauncher.getWorkspace().setScaleX(scale);
+ mLauncher.getWorkspace().setScaleY(scale);
+ mLauncher.getHotseat().setScaleX(scale);
+ mLauncher.getHotseat().setScaleY(scale);
+ }
+
void addScrimLayer() {
SurfaceControl parent = mLauncherTarget != null ? mLauncherTarget.leash : null;
if (parent == null || !parent.isValid()) {
@@ -500,6 +521,10 @@
if (mScrimLayer != null) {
removeScrimLayer();
}
+ if (Flags.predictiveBackToHomePolish() && !mLauncher.getWorkspace().isOverlayShown()
+ && !mLauncher.isInState(LauncherState.ALL_APPS)) {
+ setLauncherScale(ScalingWorkspaceRevealAnim.MAX_SIZE);
+ }
}
private void startTransitionAnimations(BackAnimState backAnim) {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 0ddd87b..7dd2f2e 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -331,7 +331,7 @@
protected void playScalingRevealAnimation() {
if (mContainer != null) {
new ScalingWorkspaceRevealAnim(mContainer, mSiblingAnimation,
- getWindowTargetRect()).start();
+ getWindowTargetRect(), true /* playAlphaReveal */).start();
}
}
@@ -381,7 +381,7 @@
if (mContainer != null) {
new ScalingWorkspaceRevealAnim(
mContainer, null /* siblingAnimation */,
- null /* windowTargetRect */).start();
+ null /* windowTargetRect */, true /* playAlphaReveal */).start();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index 9f6360b..a6feff0 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -20,7 +20,9 @@
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl;
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.PluginManagerWrapper;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.quickstep.contextualeducation.SystemContextualEduStatsManager;
+import com.android.quickstep.util.SystemWindowManagerProxy;
import dagger.Binds;
import dagger.Module;
@@ -32,4 +34,5 @@
@Binds abstract ApiWrapper bindApiWrapper(SystemApiWrapper systemApiWrapper);
@Binds abstract ContextualEduStatsManager bindContextualEduStatsManager(
SystemContextualEduStatsManager manager);
+ @Binds abstract WindowManagerProxy bindWindowManagerProxy(SystemWindowManagerProxy proxy);
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 3a0324c..8399792 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -215,7 +215,7 @@
newAppPair.getAppContents().forEach(member -> {
member.title = "";
member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
- iconCache.getTitleAndIcon(member, member.usingLowResIcon());
+ iconCache.getTitleAndIcon(member, member.getMatchingLookupFlag());
});
MAIN_EXECUTOR.execute(() -> {
LauncherAccessibilityDelegate delegate =
diff --git a/quickstep/src/com/android/quickstep/util/BackAnimState.kt b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
index 9009eaa..4c1e1ff 100644
--- a/quickstep/src/com/android/quickstep/util/BackAnimState.kt
+++ b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
@@ -18,6 +18,7 @@
import android.animation.AnimatorSet
import android.content.Context
+import com.android.launcher3.Flags
import com.android.launcher3.LauncherAnimationRunner.AnimationResult
import com.android.launcher3.anim.AnimatorListeners.forEndCallback
import com.android.launcher3.util.RunnableList
@@ -36,14 +37,20 @@
BackAnimState {
override fun addOnAnimCompleteCallback(r: Runnable) {
- val springAnimWait = RunnableList()
- springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
- ?: springAnimWait.executeAllAndDestroy()
-
val animWait = RunnableList()
- anim?.addListener(
- forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
- ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ if (Flags.predictiveBackToHomePolish()) {
+ springAnim?.addAnimatorListener(forEndCallback(animWait::executeAllAndDestroy))
+ ?: anim?.addListener(forEndCallback(animWait::executeAllAndDestroy))
+ ?: animWait.executeAllAndDestroy()
+ } else {
+ val springAnimWait = RunnableList()
+ springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
+ ?: springAnimWait.executeAllAndDestroy()
+
+ anim?.addListener(
+ forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
+ ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ }
animWait.add(r)
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
deleted file mode 100644
index 26f482c..0000000
--- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.util
-
-import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
-import com.android.quickstep.RecentsAnimationController
-import com.android.quickstep.views.DesktopTaskView
-import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskViewType
-import com.android.systemui.shared.recents.model.ThumbnailData
-
-/**
- * Helper class for [com.android.quickstep.views.RecentsView]. This util class contains refactored
- * and extracted functions from RecentsView to facilitate the implementation of unit tests.
- */
-class RecentsViewUtils {
- /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */
- fun screenshotTasks(
- taskView: TaskView,
- recentsAnimationController: RecentsAnimationController,
- ): Map<Int, ThumbnailData> =
- taskView.taskContainers.associate {
- it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
- }
-
- /**
- * Sorts task groups to move desktop tasks to the end of the list.
- *
- * @param tasks List of group tasks to be sorted.
- * @return Sorted list of GroupTasks to be used in the RecentsView.
- */
- fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
- val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
- return otherTasks + desktopTasks
- }
-
- /** Counts [TaskView]s that are [DesktopTaskView] instances. */
- fun getDesktopTaskViewCount(taskViews: Iterable<TaskView>): Int =
- taskViews.count { it is DesktopTaskView }
-
- /** Returns a list of all large TaskView Ids from [TaskView]s */
- fun getLargeTaskViewIds(taskViews: Iterable<TaskView>): List<Int> =
- taskViews.filter { it.isLargeTile }.map { it.taskViewId }
-
- /** Counts [TaskView]s that are large tiles. */
- fun getLargeTileCount(taskViews: Iterable<TaskView>): Int = taskViews.count { it.isLargeTile }
-
- /**
- * Returns the first TaskView that should be displayed as a large tile.
- *
- * @param taskViews List of [TaskView]s
- * @param splitSelectActive current split state
- */
- fun getFirstLargeTaskView(
- taskViews: MutableIterable<TaskView>,
- splitSelectActive: Boolean,
- ): TaskView? =
- taskViews.firstOrNull { it.isLargeTile && !(splitSelectActive && it is DesktopTaskView) }
-
- /** Returns the expected focus task. */
- fun getExpectedFocusedTask(taskViews: Iterable<TaskView>): TaskView? =
- if (enableLargeDesktopWindowingTile()) taskViews.firstOrNull { it !is DesktopTaskView }
- else taskViews.firstOrNull()
-
- /**
- * Returns the [TaskView] that should be the current page during task binding, in the following
- * priorities:
- * 1. Running task
- * 2. Focused task
- * 3. First non-desktop task
- * 4. Last desktop task
- * 5. null otherwise
- */
- fun getExpectedCurrentTask(
- runningTaskView: TaskView?,
- focusedTaskView: TaskView?,
- taskViews: Iterable<TaskView>,
- ): TaskView? =
- runningTaskView
- ?: focusedTaskView
- ?: taskViews.firstOrNull { it !is DesktopTaskView }
- ?: taskViews.lastOrNull()
-
- /** Returns the first TaskView if it exists, or null otherwise. */
- fun getFirstTaskView(taskViews: Iterable<TaskView>): TaskView? = taskViews.firstOrNull()
-
- /** Returns the last TaskView if it exists, or null otherwise. */
- fun getLastTaskView(taskViews: Iterable<TaskView>): TaskView? = taskViews.lastOrNull()
-
- /**
- * Returns the first TaskView that is not large
- *
- * @param taskViews List of [TaskView]s
- */
- fun getFirstSmallTaskView(taskViews: MutableIterable<TaskView>): TaskView? =
- taskViews.firstOrNull { !it.isLargeTile }
-
- /** Returns the last TaskView that should be displayed as a large tile. */
- fun getLastLargeTaskView(taskViews: Iterable<TaskView>): TaskView? =
- taskViews.lastOrNull { it.isLargeTile }
-
- /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */
- fun getFirstTaskViewInCarousel(
- nonRunningTaskCarouselHidden: Boolean,
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- ): TaskView? =
- taskViews.firstOrNull {
- it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
- }
-
- /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */
- fun getLastTaskViewInCarousel(
- nonRunningTaskCarouselHidden: Boolean,
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- ): TaskView? =
- taskViews.lastOrNull {
- it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
- }
-
- /** Returns if any small tasks are fully visible */
- fun isAnySmallTaskFullyVisible(
- taskViews: Iterable<TaskView>,
- isTaskViewFullyVisible: (TaskView) -> Boolean,
- ): Boolean = taskViews.any { !it.isLargeTile && isTaskViewFullyVisible(it) }
-
- /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */
- fun applyAttachAlpha(
- taskViews: Iterable<TaskView>,
- runningTaskView: TaskView?,
- runningTaskAttachAlpha: Float,
- nonRunningTaskCarouselHidden: Boolean,
- ) {
- taskViews.forEach { taskView ->
- taskView.attachAlpha =
- if (taskView == runningTaskView) {
- runningTaskAttachAlpha
- } else {
- if (taskView.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden))
- 1f
- else 0f
- }
- }
- }
-
- fun TaskView.isVisibleInCarousel(
- runningTaskView: TaskView?,
- nonRunningTaskCarouselHidden: Boolean,
- ): Boolean =
- if (!nonRunningTaskCarouselHidden) true
- else getCarouselType() == runningTaskView.getCarouselType()
-
- /** Returns the carousel type of the TaskView, and default to fullscreen if it's null. */
- private fun TaskView?.getCarouselType(): TaskViewCarousel =
- if (this is DesktopTaskView) TaskViewCarousel.DESKTOP else TaskViewCarousel.FULL_SCREEN
-
- private enum class TaskViewCarousel {
- FULL_SCREEN,
- DESKTOP,
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index f719bed..63eae92 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -54,14 +54,15 @@
private val launcher: QuickstepLauncher,
siblingAnimation: RectFSpringAnim?,
windowTargetRect: RectF?,
+ playAlphaReveal: Boolean = true,
) {
companion object {
private const val FADE_DURATION_MS = 200L
private const val SCALE_DURATION_MS = 1000L
private const val MAX_ALPHA = 1f
private const val MIN_ALPHA = 0f
- private const val MAX_SIZE = 1f
- private const val MIN_SIZE = 0.85f
+ internal const val MAX_SIZE = 1f
+ internal const val MIN_SIZE = 0.85f
/**
* Custom interpolator for both the home and wallpaper scaling. Necessary because EMPHASIZED
@@ -132,21 +133,23 @@
SCALE_INTERPOLATOR,
)
- // Fade in quickly at the beginning of the animation, so the content doesn't look like it's
- // popping into existence out of nowhere.
- val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
- workspace.alpha = MIN_ALPHA
- animation.setViewAlpha(
- workspace,
- MAX_ALPHA,
- Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
- )
- hotseat.alpha = MIN_ALPHA
- animation.setViewAlpha(
- hotseat,
- MAX_ALPHA,
- Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
- )
+ if (playAlphaReveal) {
+ // Fade in quickly at the beginning of the animation, so the content doesn't look like
+ // it's popping into existence out of nowhere.
+ val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
+ workspace.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ workspace,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
+ )
+ hotseat.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ hotseat,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp),
+ )
+ }
val transitionConfig = StateAnimationConfig()
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index bdfaa48..86090d5 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.animation.Animator;
@@ -89,7 +90,7 @@
MODEL_EXECUTOR.execute(() -> {
PackageItemInfo infoInOut = new PackageItemInfo(pendingIntent.getCreatorPackage(),
pendingIntent.getCreatorUserHandle());
- mIconCache.getTitleAndIconForApp(infoInOut, false);
+ mIconCache.getTitleAndIconForApp(infoInOut, DEFAULT_LOOKUP_FLAG);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
view.post(() -> {
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index f3b984b8..7fadc7d 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -27,7 +27,10 @@
import android.view.WindowMetrics;
import com.android.internal.policy.SystemBarUtils;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
+import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -37,22 +40,22 @@
import java.util.List;
import java.util.Set;
+import javax.inject.Inject;
+
/**
* Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher
*/
+@LauncherAppSingleton
public class SystemWindowManagerProxy extends WindowManagerProxy {
private final TISBindHelper mTISBindHelper;
- public SystemWindowManagerProxy(Context context) {
+ @Inject
+ public SystemWindowManagerProxy(@ApplicationContext Context context,
+ DaggerSingletonTracker lifecycleTracker) {
super(true);
mTISBindHelper = new TISBindHelper(context, binder -> {});
- }
-
- @Override
- public void close() {
- super.close();
- mTISBindHelper.onDestroy();
+ lifecycleTracker.addCloseable(mTISBindHelper::onDestroy);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index b573604..b238dec 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -21,6 +21,7 @@
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -46,7 +47,7 @@
// Max backoff caps at 5 mins
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Runnable mConnectionRunnable = this::internalBindToTIS;
private final Context mContext;
private final Consumer<TISBinder> mConnectionCallback;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6021b71..30052c7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -213,7 +213,6 @@
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.RecentsOrientedState;
-import com.android.quickstep.util.RecentsViewUtils;
import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
@@ -844,7 +843,7 @@
private final RecentsViewModel mRecentsViewModel;
private final RecentsViewModelHelper mHelper;
- private final RecentsViewUtils mUtils = new RecentsViewUtils();
+ private final RecentsViewUtils mUtils = new RecentsViewUtils(this);
private final Matrix mTmpMatrix = new Matrix();
@@ -905,12 +904,7 @@
@Nullable
public TaskView getFirstTaskView() {
- return mUtils.getFirstTaskView(getTaskViews());
- }
-
- @Nullable
- private TaskView getLastTaskView() {
- return mUtils.getLastTaskView(getTaskViews());
+ return mUtils.getFirstTaskView();
}
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
@@ -1802,8 +1796,7 @@
}
TaskView taskView = getTaskViewAt(mNextPage);
boolean shouldSnapToLargeTask = taskView != null && taskView.isLargeTile()
- && !mUtils.isAnySmallTaskFullyVisible(getTaskViews(),
- this::isTaskViewFullyVisible);
+ && !mUtils.isAnySmallTaskFullyVisible();
boolean shouldSnapToClearAll = mNextPage == indexOfChild(mClearAllButton);
// Snap to large tile when grid tasks aren't fully visible or the clear all button.
if (!shouldSnapToLargeTask && !shouldSnapToClearAll) {
@@ -2047,7 +2040,7 @@
}
// If the list changed, maybe the focused task doesn't exist anymore.
if (newFocusedTaskView == null) {
- newFocusedTaskView = mUtils.getExpectedFocusedTask(getTaskViews());
+ newFocusedTaskView = mUtils.getExpectedFocusedTask();
}
}
setFocusedTaskViewId(
@@ -2091,8 +2084,7 @@
targetPage = previousFocusedPage;
} else {
targetPage = indexOfChild(
- mUtils.getExpectedCurrentTask(newRunningTaskView, newFocusedTaskView,
- getTaskViews()));
+ mUtils.getExpectedCurrentTask(newRunningTaskView, newFocusedTaskView));
}
if (targetPage != -1 && mCurrentPage != targetPage) {
int finalTargetPage = targetPage;
@@ -2159,7 +2151,7 @@
* @return Number of children that are instances of DesktopTaskView
*/
private int getDesktopTaskViewCount() {
- return mUtils.getDesktopTaskViewCount(getTaskViews());
+ return mUtils.getDesktopTaskViewCount();
}
/**
@@ -3172,7 +3164,7 @@
private void applyAttachAlpha() {
// Only hide non running task carousel when it's fully off screen, otherwise it needs to
// be visible to move to on screen.
- mUtils.applyAttachAlpha(getTaskViews(), getRunningTaskView(), mRunningTaskAttachAlpha,
+ mUtils.applyAttachAlpha(
/*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress == 1f);
}
@@ -3262,7 +3254,7 @@
// Horizontal grid translation for each task
float[] gridTranslations = new float[taskCount];
- TaskView lastLargeTaskView = mUtils.getLastLargeTaskView(getTaskViews());
+ TaskView lastLargeTaskView = mUtils.getLastLargeTaskView();
int lastLargeTaskIndex =
(lastLargeTaskView == null) ? Integer.MAX_VALUE : indexOfChild(lastLargeTaskView);
Set<Integer> largeTasksIndices = new HashSet<>();
@@ -3800,7 +3792,7 @@
boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
int topGridRowSize = mTopRowIdSet.size();
- int numLargeTiles = mUtils.getLargeTileCount(getTaskViews());
+ int numLargeTiles = mUtils.getLargeTileCount();
int bottomGridRowSize = taskCount - mTopRowIdSet.size() - numLargeTiles;
boolean topRowLonger = topGridRowSize > bottomGridRowSize;
boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
@@ -3931,8 +3923,8 @@
int slidingTranslation = 0;
if (isSlidingTasks) {
int nextSnappedPage = isStagingFocusedTask
- ? indexOfChild(mUtils.getFirstSmallTaskView(getTaskViews()))
- : mUtils.getDesktopTaskViewCount(getTaskViews());
+ ? indexOfChild(mUtils.getFirstSmallTaskView())
+ : mUtils.getDesktopTaskViewCount();
slidingTranslation = getPagedOrientationHandler().getPrimaryScroll(this)
- getScrollForPage(nextSnappedPage);
slidingTranslation += mIsRtl ? newClearAllShortTotalWidthTranslation
@@ -4254,8 +4246,7 @@
// Snap to latest large tile page after dismissing the
// last grid task. This will prevent snapping to page 0 when
// desktop task is visible as large tile.
- pageToSnapTo = indexOfChild(
- mUtils.getLastLargeTaskView(getTaskViews()));
+ pageToSnapTo = indexOfChild(mUtils.getLastLargeTaskView());
}
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
@@ -4549,7 +4540,7 @@
// Init task grid nav helper with top/bottom id arrays.
TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
- getBottomRowIdArray(), mUtils.getLargeTaskViewIds(getTaskViews()));
+ getBottomRowIdArray(), mUtils.getLargeTaskViewIds());
// Get current page's task view ID.
TaskView currentPageTaskView = getCurrentPageTaskView();
@@ -4752,11 +4743,11 @@
@Nullable
public TaskView getLastLargeTaskView() {
- return mUtils.getLastLargeTaskView(getTaskViews());
+ return mUtils.getLastLargeTaskView();
}
public int getLargeTilesCount() {
- return mUtils.getLargeTileCount(getTaskViews());
+ return mUtils.getLargeTileCount();
}
@Nullable
@@ -4897,7 +4888,7 @@
int modalMidpoint = getCurrentPage();
TaskView carouselHiddenMidpointTask = runningTask != null ? runningTask
: mUtils.getFirstTaskViewInCarousel(/*nonRunningTaskCarouselHidden=*/true,
- getTaskViews(), null);
+ /*runningTaskView=*/null);
int carouselHiddenMidpoint = indexOfChild(carouselHiddenMidpointTask);
boolean shouldCalculateOffsetForAllTasks = showAsGrid
&& (enableGridOnlyOverview() || enableLargeDesktopWindowingTile())
@@ -5228,17 +5219,20 @@
SplitAnimationTimings timings = AnimUtils.getDeviceOverviewToSplitTimings(
mContainer.getDeviceProfile().isTablet);
if (enableLargeDesktopWindowingTile()) {
- for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = requireTaskViewAt(i);
+ TaskView currentPageTaskView = getCurrentPageTaskView();
+ TaskView nextPageTaskView = getTaskViewAt(mCurrentPage + 1);
+ TaskView previousPageTaskView = getTaskViewAt(mCurrentPage - 1);
+ for (TaskView taskView : getTaskViews()) {
if (taskView instanceof DesktopTaskView) {
// Setting pivot to scale down from screen centre.
- if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) {
- float pivotX;
- if (i == mCurrentPage - 1) {
+ if (taskView == previousPageTaskView || taskView == currentPageTaskView
+ || taskView == nextPageTaskView) {
+ float pivotX = 0f;
+ if (taskView == previousPageTaskView) {
pivotX = mIsRtl ? taskView.getWidth() / 2f - mPageSpacing
- taskView.getWidth()
: taskView.getWidth() / 2f + mPageSpacing + taskView.getWidth();
- } else if (i == mCurrentPage) {
+ } else if (taskView == currentPageTaskView) {
pivotX = taskView.getWidth() / 2f;
} else {
pivotX = mIsRtl ? taskView.getWidth() + mPageSpacing
@@ -5564,7 +5558,7 @@
mTaskViewDeadZoneRect.setEmpty();
if (hasTaskViews()) {
final View firstTaskView = getFirstTaskView();
- getLastTaskView().getHitRect(mTaskViewDeadZoneRect);
+ mUtils.getLastTaskView().getHitRect(mTaskViewDeadZoneRect);
mTaskViewDeadZoneRect.union(firstTaskView.getLeft(), firstTaskView.getTop(),
firstTaskView.getRight(),
firstTaskView.getBottom());
@@ -6112,17 +6106,15 @@
if (mShowAsGridLastOnLayout) {
// For grid Overview, it always start if a large tile (focused task or desktop task) if
// they exist, otherwise it start with the first task.
- TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews(),
- isSplitSelectionActive());
+ TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView();
if (firstLargeTaskView != null) {
firstView = firstLargeTaskView;
} else {
- firstView = mUtils.getFirstSmallTaskView(getTaskViews());
+ firstView = mUtils.getFirstSmallTaskView();
}
} else {
firstView = mUtils.getFirstTaskViewInCarousel(
- /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0,
- getTaskViews(), getRunningTaskView());
+ /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0);
}
return indexOfChild(firstView);
}
@@ -6139,12 +6131,11 @@
if (lastGridTaskView != null) {
lastView = lastGridTaskView;
} else {
- lastView = mUtils.getLastLargeTaskView(getTaskViews());
+ lastView = mUtils.getLastLargeTaskView();
}
} else {
lastView = mUtils.getLastTaskViewInCarousel(
- /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0,
- getTaskViews(), getRunningTaskView());
+ /*nonRunningTaskCarouselHidden=*/mDesktopCarouselDetachProgress > 0);
}
return indexOfChild(lastView);
}
@@ -6186,10 +6177,12 @@
}
}
- final int taskCount = getTaskViewCount();
int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
- for (int i = 0; i < taskCount; i++) {
- TaskView taskView = requireTaskViewAt(i);
+ for (int i = 0; i < getChildCount(); i++) {
+ TaskView taskView = getTaskViewAt(i);
+ if (taskView == null) {
+ continue;
+ }
float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
int pageScroll = newPageScrolls[i] + Math.round(scrollDiff);
if ((mIsRtl && pageScroll < lastTaskScroll)
@@ -6480,8 +6473,7 @@
return;
}
- Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView,
- mRecentsAnimationController);
+ Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView);
if (enableRefactorTaskThumbnail()) {
mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable);
} else {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
new file mode 100644
index 0000000..6eeffda
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024 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.views
+
+import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.quickstep.util.GroupTask
+import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/**
+ * Helper class for [RecentsView]. This util class contains refactored and extracted functions from
+ * RecentsView to facilitate the implementation of unit tests.
+ */
+class RecentsViewUtils(private val recentsView: RecentsView<*, *>) {
+ /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */
+ fun screenshotTasks(taskView: TaskView): Map<Int, ThumbnailData> {
+ val recentsAnimationController = recentsView.recentsAnimationController ?: return emptyMap()
+ return taskView.taskContainers.associate {
+ it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id)
+ }
+ }
+
+ /**
+ * Sorts task groups to move desktop tasks to the end of the list.
+ *
+ * @param tasks List of group tasks to be sorted.
+ * @return Sorted list of GroupTasks to be used in the RecentsView.
+ */
+ fun sortDesktopTasksToFront(tasks: List<GroupTask>): List<GroupTask> {
+ val (desktopTasks, otherTasks) = tasks.partition { it.taskViewType == TaskViewType.DESKTOP }
+ return otherTasks + desktopTasks
+ }
+
+ /** Counts [TaskView]s that are [DesktopTaskView] instances. */
+ fun getDesktopTaskViewCount(): Int = recentsView.taskViews.count { it is DesktopTaskView }
+
+ /** Returns a list of all large TaskView Ids from [TaskView]s */
+ fun getLargeTaskViewIds(): List<Int> =
+ recentsView.taskViews.filter { it.isLargeTile }.map { it.taskViewId }
+
+ /** Counts [TaskView]s that are large tiles. */
+ fun getLargeTileCount(): Int = recentsView.taskViews.count { it.isLargeTile }
+
+ /** Returns the first TaskView that should be displayed as a large tile. */
+ fun getFirstLargeTaskView(): TaskView? =
+ recentsView.taskViews.firstOrNull {
+ it.isLargeTile && !(recentsView.isSplitSelectionActive && it is DesktopTaskView)
+ }
+
+ /** Returns the expected focus task. */
+ fun getExpectedFocusedTask(): TaskView? =
+ if (enableLargeDesktopWindowingTile())
+ recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
+ else recentsView.taskViews.firstOrNull()
+
+ /**
+ * Returns the [TaskView] that should be the current page during task binding, in the following
+ * priorities:
+ * 1. Running task
+ * 2. Focused task
+ * 3. First non-desktop task
+ * 4. Last desktop task
+ * 5. null otherwise
+ */
+ fun getExpectedCurrentTask(runningTaskView: TaskView?, focusedTaskView: TaskView?): TaskView? =
+ runningTaskView
+ ?: focusedTaskView
+ ?: recentsView.taskViews.firstOrNull { it !is DesktopTaskView }
+ ?: recentsView.taskViews.lastOrNull()
+
+ /** Returns the first TaskView if it exists, or null otherwise. */
+ fun getFirstTaskView(): TaskView? = recentsView.taskViews.firstOrNull()
+
+ /** Returns the last TaskView if it exists, or null otherwise. */
+ fun getLastTaskView(): TaskView? = recentsView.taskViews.lastOrNull()
+
+ /** Returns the first TaskView that is not large */
+ fun getFirstSmallTaskView(): TaskView? = recentsView.taskViews.firstOrNull { !it.isLargeTile }
+
+ /** Returns the last TaskView that should be displayed as a large tile. */
+ fun getLastLargeTaskView(): TaskView? = recentsView.taskViews.lastOrNull { it.isLargeTile }
+
+ @JvmOverloads
+ /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */
+ fun getFirstTaskViewInCarousel(
+ nonRunningTaskCarouselHidden: Boolean,
+ runningTaskView: TaskView? = recentsView.runningTaskView,
+ ): TaskView? =
+ recentsView.taskViews.firstOrNull {
+ it.isVisibleInCarousel(runningTaskView, nonRunningTaskCarouselHidden)
+ }
+
+ /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */
+ fun getLastTaskViewInCarousel(nonRunningTaskCarouselHidden: Boolean): TaskView? =
+ recentsView.taskViews.lastOrNull {
+ it.isVisibleInCarousel(recentsView.runningTaskView, nonRunningTaskCarouselHidden)
+ }
+
+ /** Returns if any small tasks are fully visible */
+ fun isAnySmallTaskFullyVisible(): Boolean =
+ recentsView.taskViews.any { !it.isLargeTile && recentsView.isTaskViewFullyVisible(it) }
+
+ /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */
+ fun applyAttachAlpha(nonRunningTaskCarouselHidden: Boolean) {
+ recentsView.taskViews.forEach { taskView ->
+ taskView.attachAlpha =
+ if (taskView == recentsView.runningTaskView) {
+ RUNNING_TASK_ATTACH_ALPHA.get(recentsView)
+ } else {
+ if (
+ taskView.isVisibleInCarousel(
+ recentsView.runningTaskView,
+ nonRunningTaskCarouselHidden,
+ )
+ )
+ 1f
+ else 0f
+ }
+ }
+ }
+
+ fun TaskView.isVisibleInCarousel(
+ runningTaskView: TaskView?,
+ nonRunningTaskCarouselHidden: Boolean,
+ ): Boolean =
+ if (!nonRunningTaskCarouselHidden) true
+ else getCarouselType() == runningTaskView.getCarouselType()
+
+ /** Returns the carousel type of the TaskView, and default to fullscreen if it's null. */
+ private fun TaskView?.getCarouselType(): TaskViewCarousel =
+ if (this is DesktopTaskView) TaskViewCarousel.DESKTOP else TaskViewCarousel.FULL_SCREEN
+
+ private enum class TaskViewCarousel {
+ FULL_SCREEN,
+ DESKTOP,
+ }
+}
diff --git a/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java b/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
index bc989dc..c319cb1 100644
--- a/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/launcher3/util/StateManagerProtoLogProxy.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableStateManagerProtoLog;
import static com.android.quickstep.util.QuickstepProtoLogGroup.LAUNCHER_STATE_MANAGER;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import androidx.annotation.NonNull;
@@ -30,7 +31,7 @@
public static void logGoToState(
@NonNull Object fromState, @NonNull Object toState, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER,
"StateManager.goToState: fromState: %s, toState: %s, partial trace:\n%s",
fromState,
@@ -40,7 +41,7 @@
public static void logCreateAtomicAnimation(
@NonNull Object fromState, @NonNull Object toState, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.createAtomicAnimation: "
+ "fromState: %s, toState: %s, partial trace:\n%s",
fromState,
@@ -49,17 +50,17 @@
}
public static void logOnStateTransitionStart(@NonNull Object state) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.onStateTransitionStart: state: %s", state);
}
public static void logOnStateTransitionEnd(@NonNull Object state) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER, "StateManager.onStateTransitionEnd: state: %s", state);
}
public static void logCancelAnimation(boolean animationOngoing, @NonNull String trace) {
- if (!enableStateManagerProtoLog()) return;
+ if (!enableStateManagerProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(LAUNCHER_STATE_MANAGER,
"StateManager.cancelAnimation: animation ongoing: %b, partial trace:\n%s",
animationOngoing,
diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
index f25f6f4..be1a4e8 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java
@@ -37,6 +37,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
import static com.android.quickstep.util.QuickstepProtoLogGroup.ACTIVE_GESTURE_LOG;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import android.graphics.Point;
import android.graphics.RectF;
@@ -62,7 +63,7 @@
public static void logLauncherDestroyed() {
ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
- if (!enableActiveGestureProtoLog()) return;
+ if (isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Launcher destroyed");
}
@@ -70,7 +71,7 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "AbsSwipeUpHandler.onRecentsAnimationCanceled",
/* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onRecentsAnimationCanceled");
}
@@ -78,7 +79,7 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "RecentsAnimationCallbacks.onAnimationFinished",
ON_FINISH_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onAnimationFinished");
}
@@ -86,27 +87,27 @@
ActiveGestureLog.INSTANCE.addLog(
"AbsSwipeUpHandler.cancelCurrentAnimation",
ActiveGestureErrorDetector.GestureEvent.CANCEL_CURRENT_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.cancelCurrentAnimation");
}
public static void logAbsSwipeUpHandlerOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("AbsSwipeUpHandler.onTasksAppeared: "
+ "force finish recents animation complete; clearing state callback.");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.onTasksAppeared: "
+ "force finish recents animation complete; clearing state callback.");
}
public static void logHandOffAnimation() {
ActiveGestureLog.INSTANCE.addLog("AbsSwipeUpHandler.handOffAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "AbsSwipeUpHandler.handOffAnimation");
}
public static void logFinishRecentsAnimationOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimationOnTasksAppeared");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimationOnTasksAppeared");
}
@@ -114,14 +115,14 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "RecentsAnimationCallbacks.onAnimationCanceled",
/* gestureEvent= */ ON_CANCEL_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onAnimationCanceled");
}
public static void logRecentsAnimationCallbacksOnTasksAppeared() {
ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared",
ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onTasksAppeared");
}
@@ -129,39 +130,39 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "TaskAnimationManager.startRecentsAnimation",
/* gestureEvent= */ START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TaskAnimationManager.startRecentsAnimation");
}
public static void logLaunchingSideTaskFailed() {
ActiveGestureLog.INSTANCE.addLog("Unable to launch side task (no recents)");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Unable to launch side task (no recents)");
}
public static void logContinueRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog(/* event= */ "continueRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "continueRecentsAnimation");
}
public static void logCleanUpRecentsAnimationSkipped() {
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "cleanUpRecentsAnimation skipped due to wrong callbacks");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "cleanUpRecentsAnimation skipped due to wrong callbacks");
}
public static void logCleanUpRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "cleanUpRecentsAnimation");
}
public static void logOnInputEventUserLocked() {
ActiveGestureLog.INSTANCE.addLog(
"TIS.onInputEvent: Cannot process input event: user is locked");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Cannot process input event: user is locked");
}
@@ -171,7 +172,7 @@
+ "but a previously-requested recents animation hasn't started. "
+ "Ignoring all following motion events.",
RECENTS_ANIMATION_START_PENDING);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: A new gesture has been started, "
+ "but a previously-requested recents animation hasn't started. "
+ "Ignoring all following motion events.");
@@ -180,53 +181,53 @@
public static void logOnInputEventThreeButtonNav() {
ActiveGestureLog.INSTANCE.addLog("TIS.onInputEvent: Cannot process input event: "
+ "using 3-button nav and event is not a trackpad event");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onInputEvent: Cannot process input event: "
+ "using 3-button nav and event is not a trackpad event");
}
public static void logPreloadRecentsAnimation() {
ActiveGestureLog.INSTANCE.addLog("preloadRecentsAnimation");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "preloadRecentsAnimation");
}
public static void logRecentTasksMissing() {
ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Null mRecentTasks");
}
public static void logExecuteHomeCommand() {
ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(HOME)");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "OverviewCommandHelper.executeCommand(HOME)");
}
public static void logFinishRecentsAnimationCallback() {
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation-callback");
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimation-callback");
}
public static void logOnScrollerAnimationAborted() {
ActiveGestureLog.INSTANCE.addLog("scroller animation aborted",
ActiveGestureErrorDetector.GestureEvent.SCROLLER_ANIMATION_ABORTED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "scroller animation aborted");
}
public static void logInputConsumerBecameActive(@NonNull String consumerName) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"%s became active", consumerName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "%s became active", consumerName);
}
public static void logTaskLaunchFailed(int launchedTaskId) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launch failed, task (id=%d) finished mid transition", launchedTaskId));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Launch failed, task (id=%d) finished mid transition", launchedTaskId);
}
@@ -234,7 +235,7 @@
public static void logOnPageEndTransition(int nextPageIndex) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onPageEndTransition: current page index updated: %d", nextPageIndex));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onPageEndTransition: current page index updated: %d", nextPageIndex);
}
@@ -244,7 +245,7 @@
"Quick switch from home fallback case: The TaskView at index %d is missing.",
taskIndex),
QUICK_SWITCH_FROM_HOME_FALLBACK);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Quick switch from home fallback case: The TaskView at index %d is missing.",
taskIndex);
@@ -255,7 +256,7 @@
"Quick switch from home failed: TaskViews at indices %d and 0 are missing.",
taskIndex),
QUICK_SWITCH_FROM_HOME_FAILED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Quick switch from home failed: TaskViews at indices %d and 0 are missing.",
taskIndex);
@@ -265,42 +266,42 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"finishRecentsAnimation: %b", toRecents),
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRecentsAnimation: %b", toRecents);
}
public static void logSetEndTarget(@NonNull String target) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"setEndTarget %s", target), /* gestureEvent= */ SET_END_TARGET);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "setEndTarget %s", target);
}
public static void logStartHomeIntent(@NonNull String reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"OverviewComponentObserver.startHomeIntent: %s", reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "OverviewComponentObserver.startHomeIntent: %s", reason);
}
public static void logRunningTaskPackage(@NonNull String packageName) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Current running task package name=%s", packageName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Current running task package name=%s", packageName);
}
public static void logSysuiStateFlags(@NonNull String stateFlags) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Current SystemUi state flags=%s", stateFlags));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Current SystemUi state flags=%s", stateFlags);
}
public static void logSetInputConsumer(@NonNull String consumerName, @NonNull String reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"setInputConsumer: %s. reason(s):%s", consumerName, reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"setInputConsumer: %s. reason(s):%s", consumerName, reason);
}
@@ -312,7 +313,7 @@
+ "one (%s) was excluded from recents",
otherTaskPackage,
runningTaskPackage));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Changing active task to %s because the previous task running on top of this "
+ "one (%s) was excluded from recents",
@@ -328,7 +329,7 @@
/* gestureEvent= */ action == ACTION_DOWN
? MOTION_DOWN
: MOTION_UP);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onMotionEvent(%d, %d): %s, %s", x, y, actionString, classification);
}
@@ -341,7 +342,7 @@
classification,
pointerCount),
MOTION_MOVE);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"onMotionEvent: %s, %s, pointerCount: %d", action, classification, pointerCount);
}
@@ -350,7 +351,7 @@
@NonNull String action, @NonNull String classification) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onMotionEvent: %s, %s", action, classification));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "onMotionEvent: %s, %s", action, classification);
}
@@ -362,7 +363,7 @@
startNavMode,
currentNavMode),
NAVIGATION_MODE_SWITCHED);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Navigation mode switched mid-gesture (%s -> %s); "
+ "cancelling gesture.",
@@ -373,7 +374,7 @@
public static void logUnknownInputEvent(@NonNull String event) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"TIS.onInputEvent: Cannot process input event: received unknown event %s", event));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TIS.onInputEvent: Cannot process input event: received unknown event %s", event);
}
@@ -381,14 +382,14 @@
public static void logFinishRunningRecentsAnimation(boolean toHome) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"finishRunningRecentsAnimation: %b", toHome));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "finishRunningRecentsAnimation: %b", toHome);
}
public static void logOnRecentsAnimationStartCancelled() {
ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onAnimationStart (canceled): 0",
/* gestureEvent= */ ON_START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "RecentsAnimationCallbacks.onAnimationStart (canceled): 0");
}
@@ -396,7 +397,7 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"RecentsAnimationCallbacks.onAnimationStart (canceled): %d", appCount),
/* gestureEvent= */ ON_START_RECENTS_ANIMATION);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"RecentsAnimationCallbacks.onAnimationStart (canceled): %d", appCount);
}
@@ -406,7 +407,7 @@
"TaskAnimationManager.startRecentsAnimation(%s): "
+ "Setting mRecentsAnimationStartPending = false",
callback));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TaskAnimationManager.startRecentsAnimation(%s): "
+ "Setting mRecentsAnimationStartPending = false",
@@ -418,7 +419,7 @@
"TaskAnimationManager.startRecentsAnimation: "
+ "Setting mRecentsAnimationStartPending = %b",
value));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"TaskAnimationManager.startRecentsAnimation: "
+ "Setting mRecentsAnimationStartPending = %b",
@@ -428,28 +429,28 @@
public static void logLaunchingSideTask(int taskId) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launching side task id=%d", taskId));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "Launching side task id=%d", taskId);
}
public static void logOnInputEventActionDown(@NonNull ActiveGestureLog.CompoundString reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"TIS.onMotionEvent: ").append(reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: %s", reason.toString());
}
public static void logStartNewTask(@NonNull ActiveGestureLog.CompoundString tasks) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"Launching task: ").append(tasks));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "TIS.onMotionEvent: %s", tasks.toString());
}
public static void logMotionPauseDetectorEvent(@NonNull ActiveGestureLog.CompoundString event) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"MotionPauseDetector: ").append(event));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "MotionPauseDetector: %s", event.toString());
}
@@ -457,7 +458,7 @@
@NonNull ActiveGestureLog.CompoundString reason) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"handleTaskAppeared check failed: ").append(reason));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "handleTaskAppeared check failed: %s", reason.toString());
}
@@ -469,7 +470,7 @@
@NonNull String string,
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
ActiveGestureLog.INSTANCE.addLog(string, gestureEvent);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "%s", string);
}
@@ -477,7 +478,7 @@
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"onSettledOnEndTarget %s", endTarget),
/* gestureEvent= */ ON_SETTLED_ON_END_TARGET);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG, "onSettledOnEndTarget %s", endTarget);
}
@@ -488,7 +489,7 @@
velocityY,
angle),
velocityX == 0 && velocityY == 0 ? INVALID_VELOCITY_ON_SWIPE_UP : null);
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"calculateEndTarget: velocities=(x=%fdp/ms, y=%fdp/ms), angle=%f",
velocityX,
@@ -501,7 +502,7 @@
"Forcefully finishing recents animation: Unexpected task appeared id=%d, pkg=%s",
taskId,
packageName));
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"Forcefully finishing recents animation: Unexpected task appeared id=%d, pkg=%s",
taskId,
@@ -511,7 +512,7 @@
public static void logCreateTouchRegionForDisplay(int displayRotation,
@NonNull Point displaySize, @NonNull RectF swipeRegion, @NonNull RectF ohmRegion,
int gesturalHeight, int largerGesturalHeight, @NonNull String reason) {
- if (!enableActiveGestureProtoLog()) return;
+ if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(ACTIVE_GESTURE_LOG,
"OrientationTouchTransformer.createRegionForDisplay: "
+ "dispRot=%d, dispSize=%s, swipeRegion=%s, ohmRegion=%s, "
diff --git a/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
index bb02a11..2327cfc 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
@@ -16,6 +16,8 @@
package com.android.quickstep.util;
+import android.util.Log;
+
import androidx.annotation.NonNull;
import com.android.internal.protolog.ProtoLog;
@@ -26,7 +28,7 @@
/** Enums used to interface with the ProtoLog API. */
public enum QuickstepProtoLogGroup implements IProtoLogGroup {
- ACTIVE_GESTURE_LOG(true, true, false, "ActiveGestureLog"),
+ ACTIVE_GESTURE_LOG(true, true, Constants.DEBUG_ACTIVE_GESTURE, "ActiveGestureLog"),
RECENTS_WINDOW(true, true, Constants.DEBUG_RECENTS_WINDOW, "RecentsWindow"),
LAUNCHER_STATE_MANAGER(true, true, Constants.DEBUG_STATE_MANAGER, "LauncherStateManager");
@@ -35,7 +37,23 @@
private volatile boolean mLogToLogcat;
private final @NonNull String mTag;
+ public static boolean isProtoLogInitialized() {
+ if (!Variables.sIsInitialized) {
+ Log.w(Constants.TAG,
+ "Attempting to log to ProtoLog before initializing it.",
+ new IllegalStateException());
+ }
+ return Variables.sIsInitialized;
+ }
+
public static void initProtoLog() {
+ if (Variables.sIsInitialized) {
+ Log.e(Constants.TAG,
+ "Attempting to re-initialize ProtoLog.", new IllegalStateException());
+ return;
+ }
+ Log.i(Constants.TAG, "Initializing ProtoLog.");
+ Variables.sIsInitialized = true;
ProtoLog.init(QuickstepProtoLogGroup.values());
}
@@ -95,8 +113,16 @@
this.mLogToLogcat = logToLogcat;
}
+ private static final class Variables {
+
+ private static boolean sIsInitialized = false;
+ }
+
private static final class Constants {
+ private static final String TAG = "QuickstepProtoLogGroup";
+
+ private static final boolean DEBUG_ACTIVE_GESTURE = false;
private static final boolean DEBUG_RECENTS_WINDOW = false;
private static final boolean DEBUG_STATE_MANAGER = true; // b/279059025, b/325463989
diff --git a/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
index f54ad67..2c9ae33 100644
--- a/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
+++ b/quickstep/src_protolog/com/android/quickstep/util/RecentsWindowProtoLogProxy.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableRecentsWindowProtoLog;
import static com.android.quickstep.util.QuickstepProtoLogGroup.RECENTS_WINDOW;
+import static com.android.quickstep.util.QuickstepProtoLogGroup.isProtoLogInitialized;
import androidx.annotation.NonNull;
@@ -36,17 +37,17 @@
public class RecentsWindowProtoLogProxy {
public static void logOnStateSetStart(@NonNull String stateName) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "onStateSetStart: %s", stateName);
}
public static void logOnStateSetEnd(@NonNull String stateName) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "onStateSetEnd: %s", stateName);
}
public static void logStartRecentsWindow(boolean isShown, boolean windowViewIsNull) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW,
"Starting recents window: isShow= %b, windowViewIsNull=%b",
isShown,
@@ -54,7 +55,7 @@
}
public static void logCleanup(boolean isShown) {
- if (!enableRecentsWindowProtoLog()) return;
+ if (!enableRecentsWindowProtoLog() || !isProtoLogInitialized()) return;
ProtoLog.d(RECENTS_WINDOW, "Cleaning up recents window: isShow= %b", isShown);
}
}
diff --git a/res/values/config.xml b/res/values/config.xml
index f6f3c95..a545f0c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -68,7 +68,6 @@
<string name="app_launch_tracker_class" translatable="false"></string>
<string name="test_information_handler_class" translatable="false"></string>
<string name="model_delegate_class" translatable="false"></string>
- <string name="window_manager_proxy_class" translatable="false"></string>
<string name="secondary_display_predictions_class" translatable="false"></string>
<string name="widget_holder_factory_class" translatable="false"></string>
<string name="taskbar_search_session_controller_class" translatable="false"></string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 247ee48..1fc14ec 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -1351,12 +1351,10 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
- if (getTag() instanceof ItemInfoWithIcon && !mHighResUpdateInProgress) {
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
- if (info.usingLowResIcon()) {
- mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
- .updateIconInBackground(BubbleTextView.this, info);
- }
+ if (getTag() instanceof ItemInfoWithIcon info && !mHighResUpdateInProgress
+ && info.getMatchingLookupFlag().useLowRes()) {
+ mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
+ .updateIconInBackground(BubbleTextView.this, info);
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 425f277..89d54f8 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -131,6 +132,10 @@
ItemInfo item = d.dragInfo;
if (canRemove(item)) {
mDropTargetHandler.onDeleteComplete(item);
+ } else if (mText == getResources().getText(R.string.remove_drop_target_label)) {
+ Log.wtf("b/379606516", "If the drop target text is 'remove', then"
+ + " users should always be able to delete the item from launcher's db."
+ + " Invalid drag ItemInfo: " + item);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index dddc43f..0104b6c 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -57,6 +57,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.provider.RestoreDbTask;
+import com.android.launcher3.settings.SettingsActivity;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
@@ -259,8 +260,12 @@
}
});
if (Flags.oneGridSpecs()) {
- mLandscapeModePreferenceListener = (String s) -> {
- if (isFixedLandscape != FIXED_LANDSCAPE_MODE.get(context)) {
+ mLandscapeModePreferenceListener = (String preference_name) -> {
+ // Here we need both conditions even though they might seem redundant but because
+ // the update happens in the executable there can be race conditions and this avoids
+ // it.
+ if (isFixedLandscape != FIXED_LANDSCAPE_MODE.get(context)
+ && SettingsActivity.FIXED_LANDSCAPE_MODE.equals(preference_name)) {
MAIN_EXECUTOR.execute(() -> {
Trace.beginSection("InvariantDeviceProfile#setFixedLandscape");
onConfigChanged(context.getApplicationContext());
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index ebcb5da..9060691 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -631,7 +631,7 @@
Drawable mainIcon = null;
Drawable badge = null;
- if ((info instanceof ItemInfoWithIcon iiwi) && !iiwi.usingLowResIcon()) {
+ if ((info instanceof ItemInfoWithIcon iiwi) && !iiwi.getMatchingLookupFlag().useLowRes()) {
badge = iiwi.bitmap.getBadgeDrawable(context, useTheme);
}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 1e3df1e..340fb02 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -32,6 +32,7 @@
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.window.RefreshRateTracker;
+import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import dagger.BindsInstance;
@@ -60,6 +61,7 @@
PluginManagerWrapper getPluginManagerWrapper();
VibratorWrapper getVibratorWrapper();
MSDLPlayerWrapper getMSDLPlayerWrapper();
+ WindowManagerProxy getWmProxy();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index e7c4024..ab4105c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -17,6 +17,7 @@
package com.android.launcher3.icons;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -51,6 +52,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.cache.BaseIconCache;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.icons.cache.CachedObject;
import com.android.launcher3.icons.cache.CachedObjectCachingLogic;
import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
@@ -163,12 +165,12 @@
Supplier<ItemInfoWithIcon> task;
if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
task = () -> {
- getTitleAndIcon(info, false);
+ getTitleAndIcon(info, DEFAULT_LOOKUP_FLAG);
return info;
};
} else if (info instanceof PackageItemInfo pii) {
task = () -> {
- getTitleAndIconForApp(pii, false);
+ getTitleAndIconForApp(pii, DEFAULT_LOOKUP_FLAG);
return pii;
};
} else {
@@ -207,7 +209,7 @@
public synchronized void updateTitleAndIcon(AppInfo application) {
CacheEntry entry = cacheLocked(application.componentName,
application.user, () -> null, LauncherActivityCachingLogic.INSTANCE,
- application.usingLowResIcon() ? LookupFlag.USE_LOW_RES : LookupFlag.DEFAULT);
+ application.getMatchingLookupFlag());
if (entry.bitmap != null || !isDefaultIcon(entry.bitmap, application.user)) {
applyCacheEntry(entry, application);
}
@@ -218,11 +220,11 @@
*/
@SuppressWarnings("NewApi")
public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
- LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+ LauncherActivityInfo activityInfo, @NonNull CacheLookupFlag lookupFlag) {
boolean isAppArchived = Flags.enableSupportForArchiving() && activityInfo != null
&& activityInfo.getActivityInfo().isArchived;
// If we already have activity info, no need to use package icon
- getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon);
+ getTitleAndIcon(info, () -> activityInfo, lookupFlag.withUsePackageIcon(isAppArchived));
}
/**
@@ -252,7 +254,7 @@
user,
() -> si,
CacheableShortcutCachingLogic.INSTANCE,
- LookupFlag.SKIP_ADD_TO_MEM_CACHE).bitmap;
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()).bitmap;
if (bitmapInfo.isNullOrLowRes()) {
bitmapInfo = getDefaultIcon(user);
}
@@ -291,12 +293,12 @@
appInfo.intent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setComponent(cn);
- getTitleAndIcon(appInfo, false);
+ getTitleAndIcon(appInfo, DEFAULT_LOOKUP_FLAG);
return appInfo;
}
}
PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
- getTitleAndIconForApp(pkgInfo, false);
+ getTitleAndIconForApp(pkgInfo, DEFAULT_LOOKUP_FLAG);
return pkgInfo;
}
@@ -304,7 +306,9 @@
* Fill in {@param info} with the icon and label. If the
* corresponding activity is not found, it reverts to the package icon.
*/
- public synchronized void getTitleAndIcon(ItemInfoWithIcon info, boolean useLowResIcon) {
+ public synchronized void getTitleAndIcon(
+ @NonNull ItemInfoWithIcon info,
+ @NonNull CacheLookupFlag lookupFlag) {
// null info means not installed, but if we have a component from the intent then
// we should still look in the cache for restored app icons.
if (info.getTargetComponent() == null) {
@@ -314,7 +318,7 @@
} else {
Intent intent = info.getIntent();
getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
- true, useLowResIcon);
+ lookupFlag.withUsePackageIcon());
}
}
@@ -324,7 +328,7 @@
public synchronized String getTitleNoCache(CachedObject info) {
CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info,
CachedObjectCachingLogic.INSTANCE,
- LookupFlag.USE_LOW_RES | LookupFlag.SKIP_ADD_TO_MEM_CACHE);
+ DEFAULT_LOOKUP_FLAG.withUseLowRes().withSkipAddToMemCache());
return Utilities.trim(entry.title);
}
@@ -334,12 +338,9 @@
public synchronized void getTitleAndIcon(
@NonNull ItemInfoWithIcon infoInOut,
@NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
- boolean usePkgIcon, boolean useLowResIcon) {
- int lookupFlags = LookupFlag.DEFAULT;
- if (usePkgIcon) lookupFlags |= LookupFlag.USE_PACKAGE_ICON;
- if (useLowResIcon) lookupFlags |= LookupFlag.USE_LOW_RES;
+ @NonNull CacheLookupFlag lookupFlag) {
CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
- activityInfoProvider, LauncherActivityCachingLogic.INSTANCE, lookupFlags);
+ activityInfoProvider, LauncherActivityCachingLogic.INSTANCE, lookupFlag);
applyCacheEntry(entry, infoInOut);
}
@@ -441,7 +442,7 @@
/* user = */ sectionKey.first,
() -> duplicateIconRequests.get(0).launcherActivityInfo,
LauncherActivityCachingLogic.INSTANCE,
- sectionKey.second ? LookupFlag.USE_LOW_RES : LookupFlag.DEFAULT,
+ DEFAULT_LOOKUP_FLAG.withUseLowRes(sectionKey.second),
c);
for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
@@ -515,9 +516,10 @@
* Fill in {@param infoInOut} with the corresponding icon and label.
*/
public synchronized void getTitleAndIconForApp(
- @NonNull final PackageItemInfo infoInOut, final boolean useLowResIcon) {
+ @NonNull final PackageItemInfo infoInOut,
+ @NonNull CacheLookupFlag lookupFlag) {
CacheEntry entry = getEntryForPackageLocked(
- infoInOut.packageName, infoInOut.user, useLowResIcon);
+ infoInOut.packageName, infoInOut.user, lookupFlag.useLowRes());
applyCacheEntry(entry, infoInOut);
if (infoInOut.widgetCategory == NO_CATEGORY) {
return;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 55bcb70..b936adf 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -194,8 +194,7 @@
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
wii.title = "";
wii.bitmap = cache.getDefaultIcon(item.user);
- cache.getTitleAndIcon(wii,
- ((WorkspaceItemInfo) itemInfo).usingLowResIcon());
+ cache.getTitleAndIcon(wii, wii.getMatchingLookupFlag());
}
}
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 7bc9273..98f9afd 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
@@ -151,7 +152,7 @@
return;
}
if (loadIcon) {
- mIconCache.getTitleAndIcon(info, activityInfo, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(info, activityInfo, DEFAULT_LOOKUP_FLAG);
info.sectionName = mIndex.computeSectionName(info.title);
} else {
info.title = "";
@@ -177,7 +178,7 @@
AppInfo promiseAppInfo = new AppInfo(installInfo);
if (loadIcon) {
- mIconCache.getTitleAndIcon(promiseAppInfo, promiseAppInfo.usingLowResIcon());
+ mIconCache.getTitleAndIcon(promiseAppInfo, promiseAppInfo.getMatchingLookupFlag());
promiseAppInfo.sectionName = mIndex.computeSectionName(promiseAppInfo.title);
} else {
promiseAppInfo.title = "";
@@ -338,7 +339,7 @@
} else {
Intent launchIntent = AppInfo.makeLaunchIntent(info);
- mIconCache.getTitleAndIcon(applicationInfo, info, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(applicationInfo, info, DEFAULT_LOOKUP_FLAG);
applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
applicationInfo.intent = launchIntent;
AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info,
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 66b4fd9..b544b91 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -63,7 +63,7 @@
if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
&& isValidShortcut(si) && cn != null
&& mPackages.contains(cn.getPackageName())) {
- iconCache.getTitleAndIcon(si, si.usingLowResIcon());
+ iconCache.getTitleAndIcon(si, si.getMatchingLookupFlag());
updatedShortcuts.add(si);
}
});
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index f9c6e96..c4f222f 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -308,7 +309,8 @@
}
}
LauncherAppState.getInstance(context).getIconCache()
- .getTitleAndIcon(si, () -> lai, usePackageIcon, false);
+ .getTitleAndIcon(si, () -> lai,
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon(usePackageIcon));
return Pair.create(si, null);
}
case ITEM_TYPE_DEEP_SHORTCUT: {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index c01b1b6..536d4c9 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -300,7 +301,7 @@
// the fallback icon
if (!loadIcon(info)) {
- mIconCache.getTitleAndIcon(info, false /* useLowResIcon */);
+ mIconCache.getTitleAndIcon(info, DEFAULT_LOOKUP_FLAG);
}
if (hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORED_ICON)) {
@@ -364,7 +365,8 @@
UserIconInfo userIconInfo = userCache.getUserInfo(user);
if (loadIcon) {
- mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
+ mIconCache.getTitleAndIcon(info, mActivityInfo,
+ DEFAULT_LOOKUP_FLAG.withUseLowRes(useLowResIcon));
if (mIconCache.isDefaultIcon(info.bitmap, user)) {
loadIcon(info);
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f96e959..4981949 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.icons.CacheableShortcutInfo.convertShortcutsToCacheableShortcuts;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
@@ -213,13 +214,13 @@
ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
filterCurrentWorkspaceItems(firstScreens, allItems, firstScreenItems,
new ArrayList<>() /* otherScreenItems are ignored */);
- final int launcherBroadcastInstalledApps = Settings.Secure.getInt(
+ final int disableArchivingLauncherBroadcast = Settings.Secure.getInt(
mApp.getContext().getContentResolver(),
- "launcher_broadcast_installed_apps",
- /* def= */ 0);
+ "disable_launcher_broadcast_installed_apps",
+ /* default */ 0);
boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
- && (launcherBroadcastInstalledApps == 1
- || Flags.enableFirstScreenBroadcastArchivingExtras());
+ && disableArchivingLauncherBroadcast == 0
+ && Flags.enableFirstScreenBroadcastArchivingExtras();
if (shouldAttachArchivingExtras) {
List<FirstScreenBroadcastModel> broadcastModels =
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
@@ -231,6 +232,7 @@
logASplit("Sending first screen broadcast with additional archiving Extras");
FirstScreenBroadcastHelper.sendBroadcastsForModels(mApp.getContext(), broadcastModels);
} else {
+ logASplit("Sending first screen broadcast");
mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
}
}
@@ -276,7 +278,6 @@
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
- logASplit("sendFirstScreenBroadcast finished");
// Take a break
waitForIdle();
@@ -599,10 +600,10 @@
info.rank = rank;
if (info instanceof WorkspaceItemInfo wii
- && wii.usingLowResIcon()
+ && wii.getMatchingLookupFlag().useLowRes()
&& wii.itemType == Favorites.ITEM_TYPE_APPLICATION
&& verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
- mIconCache.getTitleAndIcon(wii, false);
+ mIconCache.getTitleAndIcon(wii, DEFAULT_LOOKUP_FLAG);
} else if (info instanceof AppPairInfo api) {
api.fetchHiResIconsIfNeeded(mIconCache);
}
@@ -765,7 +766,7 @@
iconRequestInfos.add(new IconRequestInfo<>(
promiseAppInfo,
/* launcherActivityInfo= */ null,
- promiseAppInfo.usingLowResIcon()));
+ promiseAppInfo.getMatchingLookupFlag().useLowRes()));
}
}
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 5464afe..d619965 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -326,7 +326,8 @@
itemInfo.setNonResizeable(ApiWrapper.INSTANCE.get(context)
.isNonResizeableActivity(activities.get(0)));
}
- iconCache.getTitleAndIcon(itemInfo, itemInfo.usingLowResIcon());
+ iconCache.getTitleAndIcon(
+ itemInfo, itemInfo.getMatchingLookupFlag());
infoUpdated = true;
}
}
diff --git a/src/com/android/launcher3/model/SessionFailureTask.kt b/src/com/android/launcher3/model/SessionFailureTask.kt
index 0d006fa..8baf568 100644
--- a/src/com/android/launcher3/model/SessionFailureTask.kt
+++ b/src/com/android/launcher3/model/SessionFailureTask.kt
@@ -48,7 +48,7 @@
for (info in dataModel.itemsIdMap) {
if (info is WorkspaceItemInfo && info.isArchived && user == info.user) {
// Refresh icons on the workspace for archived apps.
- iconCache.getTitleAndIcon(info, info.usingLowResIcon())
+ iconCache.getTitleAndIcon(info, info.matchingLookupFlag)
updatedItems.add(info)
}
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index a27d2f1..a176465 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -4,6 +4,7 @@
import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList;
import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
@@ -203,7 +204,7 @@
// Update each package entry
IconCache iconCache = app.getIconCache();
for (PackageItemInfo p : packageItemInfoCache.values()) {
- iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
+ iconCache.getTitleAndIconForApp(p, DEFAULT_LOOKUP_FLAG.withUseLowRes());
}
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index e86b592..e23eba9 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -33,6 +33,7 @@
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.icons.CacheableShortcutInfo
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
import com.android.launcher3.logging.FileLog
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.AppPairInfo
@@ -521,7 +522,7 @@
appWidgetInfo.providerName,
appWidgetInfo.user,
)
- iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
+ iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, DEFAULT_LOOKUP_FLAG)
}
WidgetInflater.TYPE_REAL ->
WidgetSizes.updateWidgetSizeRangesAsync(
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
index 82eda36..073d0e0 100644
--- a/src/com/android/launcher3/model/data/AppPairInfo.kt
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -20,6 +20,7 @@
import com.android.launcher3.LauncherSettings
import com.android.launcher3.R
import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
import com.android.launcher3.logger.LauncherAtom
import com.android.launcher3.views.ActivityContext
@@ -72,16 +73,17 @@
val isTablet =
(ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet
return Pair(
- isTablet || !getFirstApp().isNonResizeable(),
- isTablet || !getSecondApp().isNonResizeable(),
+ isTablet || !getFirstApp().isNonResizeable,
+ isTablet || !getSecondApp().isNonResizeable,
)
}
/** Fetches high-res icons for member apps if needed. */
fun fetchHiResIconsIfNeeded(iconCache: IconCache) {
- getAppContents().stream().filter(ItemInfoWithIcon::usingLowResIcon).forEach { member ->
- iconCache.getTitleAndIcon(member, false)
- }
+ getAppContents()
+ .stream()
+ .filter { it.matchingLookupFlag.useLowRes() }
+ .forEach { member -> iconCache.getTitleAndIcon(member, DEFAULT_LOOKUP_FLAG) }
}
/**
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 6ac44ff..772ea7f 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -23,10 +23,10 @@
import androidx.annotation.Nullable;
import com.android.launcher3.Flags;
-import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.ApiWrapper;
@@ -185,10 +185,10 @@
}
/**
- * Indicates whether we're using a low res icon
+ * Returns the lookup flag to match this current state of this info
*/
- public boolean usingLowResIcon() {
- return bitmap.isLowRes();
+ public CacheLookupFlag getMatchingLookupFlag() {
+ return bitmap.getMatchingLookupFlag();
}
/**
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 9af61f0..0a5dd62 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -142,7 +142,7 @@
.put(Favorites.OPTIONS, options)
.put(Favorites.RESTORED, status);
- if (!usingLowResIcon()) {
+ if (!getMatchingLookupFlag().useLowRes()) {
writer.putIcon(bitmap, user);
}
}
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 7d7ccd3..9376518 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
@@ -210,7 +211,9 @@
}
final int activityFlags;
- if (mStateHandlerRequest != REQUEST_NONE) {
+ if (mIsFixedLandscape) {
+ activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
+ } else if (mStateHandlerRequest != REQUEST_NONE) {
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
@@ -218,8 +221,6 @@
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentStateRequest == REQUEST_LOCK) {
activityFlags = SCREEN_ORIENTATION_LOCKED;
- } else if (mIsFixedLandscape) {
- activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
} else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE
|| mHomeRotationEnabled || mForceAllowRotationForTesting) {
activityFlags = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -230,6 +231,7 @@
}
if (activityFlags != mLastActivityFlags) {
mLastActivityFlags = activityFlags;
+ Log.d("b/380940677", toString());
mRequestOrientationHandler.sendEmptyMessage(activityFlags);
}
}
@@ -257,9 +259,9 @@
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d, "
+ "mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, "
+ "mHomeRotationEnabled=%b, mForceAllowRotationForTesting=%b,"
- + " mDestroyed=%b]",
+ + " mDestroyed=%b, mIsFixedLandscape=%b]",
mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags,
mIgnoreAutoRotateSettings, mHomeRotationEnabled, mForceAllowRotationForTesting,
- mDestroyed);
+ mDestroyed, mIsFixedLandscape);
}
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 84b4a36..1d9751e 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -27,7 +27,6 @@
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT;
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT_LANDSCAPE;
import static com.android.launcher3.testing.shared.ResourceUtils.STATUS_BAR_HEIGHT_PORTRAIT;
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import static com.android.launcher3.util.RotationUtils.deltaRotation;
import static com.android.launcher3.util.RotationUtils.rotateRect;
import static com.android.launcher3.util.RotationUtils.rotateSize;
@@ -52,37 +51,33 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.testing.shared.ResourceUtils;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.DaggerSingletonObject;
import com.android.launcher3.util.NavigationMode;
-import com.android.launcher3.util.ResourceBasedOverride;
-import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
/**
* Utility class for mocking some window manager behaviours
*/
-public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
+@LauncherAppSingleton
+public class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
public static final int MIN_TABLET_WIDTH = 600;
- public static final MainThreadInitializedObject<WindowManagerProxy> INSTANCE =
- forOverride(WindowManagerProxy.class, R.string.window_manager_proxy_class);
+ public static final DaggerSingletonObject<WindowManagerProxy> INSTANCE =
+ new DaggerSingletonObject<>(LauncherBaseAppComponent::getWmProxy);
protected final boolean mTaskbarDrawnInProcess;
- /**
- * Creates a new instance of proxy, applying any overrides
- */
- public static WindowManagerProxy newInstance(Context context) {
- return Overrides.getObject(WindowManagerProxy.class, context,
- R.string.window_manager_proxy_class);
- }
-
+ @Inject
public WindowManagerProxy() {
this(false);
}
@@ -483,9 +478,6 @@
return NavigationMode.NO_BUTTON;
}
- @Override
- public void close() { }
-
/**
* @see DisplayCutout#getSafeInsets
*/
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index d164dd0..2f123a3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -234,12 +234,9 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
- if (getTag() instanceof ItemInfoWithIcon) {
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
- if (info.usingLowResIcon()) {
- mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
- .updateIconInBackground(this, info);
- }
+ if (getTag() instanceof ItemInfoWithIcon info && info.getMatchingLookupFlag().useLowRes()) {
+ mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
+ .updateIconInBackground(this, info);
}
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index f9bd5f1..df76400 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER;
import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.WIDGET_LIST_ITEM_APPEARANCE_DELAY;
import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findContentEntryForPackageUser;
@@ -51,6 +52,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.recyclerview.ViewHolderBinder;
@@ -691,8 +693,8 @@
}
@Override
- public boolean usingLowResIcon() {
- return false;
+ public CacheLookupFlag getMatchingLookupFlag() {
+ return DEFAULT_LOOKUP_FLAG;
}
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index c4519eb..c80093a 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -26,8 +26,10 @@
import android.platform.test.rule.LimitDevicesRule
import android.util.DisplayMetrics
import android.view.Surface
-import androidx.test.core.app.ApplicationProvider
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.testing.shared.ResourceUtils
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
@@ -38,6 +40,8 @@
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
import com.google.common.truth.Truth
+import dagger.BindsInstance
+import dagger.Component
import java.io.BufferedReader
import java.io.File
import java.io.PrintWriter
@@ -62,7 +66,7 @@
abstract class AbstractDeviceProfileTest {
protected val testContext: Context = InstrumentationRegistry.getInstrumentation().context
protected lateinit var context: SandboxContext
- protected open val runningContext: Context = ApplicationProvider.getApplicationContext()
+ protected open val runningContext: Context = getApplicationContext()
private val displayController: DisplayController = mock()
private val windowManagerProxy: WindowManagerProxy = mock()
private val launcherPrefs: LauncherPrefs = mock()
@@ -290,9 +294,9 @@
.thenReturn(
if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS
)
- doReturn(WindowManagerProxy.INSTANCE[runningContext].isTaskbarDrawnInProcess)
+ doReturn(WindowManagerProxy.INSTANCE[getApplicationContext()].isTaskbarDrawnInProcess)
.whenever(windowManagerProxy)
- .isTaskbarDrawnInProcess()
+ .isTaskbarDrawnInProcess
val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat()
val config =
@@ -304,8 +308,10 @@
}
val configurationContext = runningContext.createConfigurationContext(config)
context = SandboxContext(configurationContext)
+ context.initDaggerComponent(
+ DaggerAbsDPTestSandboxComponent.builder().bindWMProxy(windowManagerProxy)
+ )
context.putObject(DisplayController.INSTANCE, displayController)
- context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
whenever(launcherPrefs.get(LauncherPrefs.TASKBAR_PINNING)).thenReturn(false)
@@ -355,3 +361,14 @@
return context.resources.getIdentifier(this, "xml", context.packageName)
}
}
+
+@LauncherAppSingleton
+@Component
+interface AbsDPTestSandboxComponent : LauncherAppComponent {
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindWMProxy(proxy: WindowManagerProxy): Builder
+
+ override fun build(): AbsDPTestSandboxComponent
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
similarity index 95%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
index a006fd7..ad80b2d 100644
--- a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
@@ -32,7 +32,7 @@
*/
fun generateItemsForTest(
boards: List<CellLayoutBoard>,
- repeatAfterRange: Point
+ repeatAfterRange: Point,
): List<WorkspaceItem> {
val id = AtomicInteger(0)
val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
@@ -56,7 +56,7 @@
appWidgetProvider = "Hotseat icons don't have a provider",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
- container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ container = LauncherSettings.Favorites.CONTAINER_HOTSEAT,
)
}
var widgetEntries =
@@ -75,7 +75,7 @@
appWidgetProvider = getProvider(id.get()),
intent = "Widgets don't have intent",
type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
- container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
}
widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
@@ -95,7 +95,7 @@
appWidgetProvider = "Icons don't have providers",
intent = getIntent(id.get()),
type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
- container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
}
return widgetEntries + hotseatEntries + iconEntries
@@ -106,7 +106,7 @@
val destBoards: List<CellLayoutBoard>,
val srcSize: Point,
val targetSize: Point,
- val seed: Long
+ val seed: Long,
)
class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
@@ -122,7 +122,7 @@
boardGenerator: RandomBoardGenerator,
width: Int,
height: Int,
- boardCount: Int
+ boardCount: Int,
): List<CellLayoutBoard> {
val boards = mutableListOf<CellLayoutBoard>()
for (i in 0 until boardCount) {
@@ -130,7 +130,7 @@
boardGenerator.generateBoard(
width,
height,
- boardGenerator.getRandom(0, width * height)
+ boardGenerator.getRandom(0, width * height),
)
)
}
@@ -145,7 +145,7 @@
val targetSize =
Point(
randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
- randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+ randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
)
val destBoards =
if (isDestEmpty) {
@@ -155,7 +155,7 @@
boardGenerator = randomBoardGenerator,
width = targetSize.x,
height = targetSize.y,
- boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+ boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT),
)
}
return GridMigrationUnitTestCase(
@@ -164,12 +164,12 @@
boardGenerator = randomBoardGenerator,
width = width,
height = height,
- boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+ boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT),
),
destBoards = destBoards,
srcSize = Point(width, height),
targetSize = targetSize,
- seed = seed
+ seed = seed,
)
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
index 9b4bd71..9026748 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
import static com.android.launcher3.icons.IconCacheUpdateHandlerTestKt.waitForUpdateHandlerToFinish;
+import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
@@ -164,7 +165,7 @@
WorkspaceItemInfo info = new WorkspaceItemInfo();
info.intent = makeLaunchIntent(cn);
runOnExecutorSync(MODEL_EXECUTOR,
- () -> mIconCache.getTitleAndIcon(info, lai, false));
+ () -> mIconCache.getTitleAndIcon(info, lai, DEFAULT_LOOKUP_FLAG));
assertNotNull(info.bitmap);
assertFalse(info.bitmap.isLowRes());
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt
new file mode 100644
index 0000000..7b1851d
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/cache/CacheLookupFlagTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.launcher3.icons.cache
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.icons.cache.CacheLookupFlag.Companion.DEFAULT_LOOKUP_FLAG
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CacheLookupFlagTest {
+
+ @Test
+ fun `useLowRes preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.useLowRes())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withUseLowRes().useLowRes())
+ assertFalse(DEFAULT_LOOKUP_FLAG.withUseLowRes().withUseLowRes(false).useLowRes())
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withUseLowRes().withUseLowRes(false).withUseLowRes().useLowRes()
+ )
+ }
+
+ @Test
+ fun `usePackageIcon preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.usePackageIcon())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withUsePackageIcon().usePackageIcon())
+ assertFalse(
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon().withUsePackageIcon(false).usePackageIcon()
+ )
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withUsePackageIcon()
+ .withUsePackageIcon(false)
+ .withUsePackageIcon()
+ .usePackageIcon()
+ )
+ }
+
+ @Test
+ fun `skipAddToMemCache preserves lowRes values`() {
+ assertFalse(DEFAULT_LOOKUP_FLAG.skipAddToMemCache())
+ assertTrue(DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache().skipAddToMemCache())
+ assertFalse(
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()
+ .withSkipAddToMemCache(false)
+ .skipAddToMemCache()
+ )
+ assertTrue(
+ DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache()
+ .withSkipAddToMemCache(false)
+ .withSkipAddToMemCache()
+ .skipAddToMemCache()
+ )
+ }
+
+ @Test
+ fun `preserves multiple flags`() {
+ val flag = DEFAULT_LOOKUP_FLAG.withSkipAddToMemCache().withUseLowRes()
+
+ assertTrue(flag.skipAddToMemCache())
+ assertTrue(flag.useLowRes())
+ assertFalse(flag.usePackageIcon())
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
diff --git a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
index cc8e61d..174d716 100644
--- a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
@@ -24,8 +24,11 @@
class MockSet(override val size: Int) : Set<String> {
override fun contains(element: String): Boolean = true
+
override fun containsAll(elements: Collection<String>): Boolean = true
+
override fun isEmpty(): Boolean = false
+
override fun iterator(): Iterator<String> = listOf<String>().iterator()
}
@@ -91,7 +94,7 @@
appWidgetProvider = cursor.getString(indexWidgetProvider),
intent = cursor.getString(indexIntent),
type = cursor.getInt(indexItemType),
- container = cursor.getInt(container)
+ container = cursor.getInt(container),
)
)
}
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index a3a680e..32df84c 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.util
-import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Point
@@ -26,18 +25,21 @@
import android.view.Display
import android.view.Surface
import androidx.test.annotation.UiThreadTest
-import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener
-import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
+import dagger.BindsInstance
+import dagger.Component
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlin.math.min
@@ -51,6 +53,7 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.mockito.stubbing.Answer
@@ -60,12 +63,10 @@
@RunWith(LauncherMultivalentJUnit::class)
class DisplayControllerTest {
- private val appContext: Context = ApplicationProvider.getApplicationContext()
-
- private val context: SandboxContext = mock()
+ private val context = spy(SandboxModelContext())
private val windowManagerProxy: WindowManagerProxy = mock()
private val launcherPrefs: LauncherPrefs = mock()
- private val displayManager: DisplayManager = mock()
+ private lateinit var displayManager: DisplayManager
private val display: Display = mock()
private val resources: Resources = mock()
private val displayInfoChangeListener: DisplayInfoChangeListener = mock()
@@ -85,7 +86,7 @@
WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270),
)
private val configuration =
- Configuration(appContext.resources.configuration).apply {
+ Configuration(context.resources.configuration).apply {
densityDpi = this@DisplayControllerTest.densityDpi
screenWidthDp = (bounds[0].bounds.width() / density).toInt()
screenHeightDp = (bounds[0].bounds.height() / density).toInt()
@@ -94,8 +95,12 @@
@Before
fun setUp() {
- whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy)
- whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs)
+ context.initDaggerComponent(
+ DaggerDisplayControllerTestComponent.builder().bindWMProxy(windowManagerProxy)
+ )
+ context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
+ displayManager = context.spyService(DisplayManager::class.java)
+
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(true)
@@ -118,15 +123,13 @@
whenever(windowManagerProxy.getNavigationMode(any())).thenReturn(NavigationMode.NO_BUTTON)
// Mock context
- whenever(context.createWindowContext(any(), any(), anyOrNull())).thenReturn(context)
- whenever(context.getSystemService(eq(DisplayManager::class.java)))
- .thenReturn(displayManager)
+ doReturn(context).whenever(context).createWindowContext(any(), any(), anyOrNull())
doNothing().whenever(context).registerComponentCallbacks(any())
// Mock display
whenever(display.rotation).thenReturn(displayInfo.rotation)
- whenever(context.display).thenReturn(display)
- whenever(displayManager.getDisplay(any())).thenReturn(display)
+ doReturn(display).whenever(context).display
+ doReturn(display).whenever(displayManager).getDisplay(any())
// Mock resources
doReturn(context).whenever(context).applicationContext
@@ -143,6 +146,7 @@
// We need to reset the taskbar mode preference override even if a test throws an exception.
// Otherwise, it may break the following tests' assumptions.
DisplayController.enableTaskbarModePreferenceForTests(false)
+ context.onDestroy()
}
@Test
@@ -225,3 +229,14 @@
assertFalse(displayController.getInfo().isTransientTaskbar())
}
}
+
+@LauncherAppSingleton
+@Component
+interface DisplayControllerTestComponent : LauncherAppComponent {
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindWMProxy(proxy: WindowManagerProxy): Builder
+
+ override fun build(): DisplayControllerTestComponent
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 34cbdee..4d181ff 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -16,6 +16,9 @@
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
import com.android.launcher3.LauncherModel.LoaderTransaction
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.IS_FIRST_LOAD_AFTER_RESTORE
+import com.android.launcher3.LauncherPrefs.Companion.RESTORE_DEVICE
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
@@ -130,6 +133,8 @@
@After
fun tearDown() {
+ LauncherPrefs.get(context).removeSync(RESTORE_DEVICE)
+ LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false))
context.onDestroy()
mockitoSession.finishMocking()
}
@@ -242,84 +247,8 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When secure setting true and is restore then send installed item broadcast`() {
- // Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
- whenever(
- FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
- any(),
- any(),
- any(),
- any(),
- )
- )
- .thenReturn(listOf(expectedBroadcastModel))
-
- whenever(
- FirstScreenBroadcastHelper.sendBroadcastsForModels(
- spyContext,
- listOf(expectedBroadcastModel),
- )
- )
- .thenCallRealMethod()
-
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
- RestoreDbTask.setPending(spyContext)
-
- // When
- LoaderTask(
- app,
- bgAllAppsList,
- BgDataModel(),
- modelDelegate,
- launcherBinder,
- widgetsFilterDataProvider,
- )
- .runSyncOnBackgroundThread()
-
- // Then
- val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
- verify(spyContext).sendBroadcast(argumentCaptor.capture())
- val actualBroadcastIntent = argumentCaptor.value
- assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
- assertEquals(
- ArrayList(expectedBroadcastModel.installedWorkspaceItems),
- actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.installedHotseatItems),
- actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems"),
- )
- assertEquals(
- ArrayList(
- expectedBroadcastModel.firstScreenInstalledWidgets +
- expectedBroadcastModel.secondaryScreenInstalledWidgets
- ),
- actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingCollectionItems),
- actualBroadcastIntent.getStringArrayListExtra("folderItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
- actualBroadcastIntent.getStringArrayListExtra("workspaceItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingHotseatItems),
- actualBroadcastIntent.getStringArrayListExtra("hotseatItem"),
- )
- assertEquals(
- ArrayList(expectedBroadcastModel.pendingWidgetItems),
- actualBroadcastIntent.getStringArrayListExtra("widgetItem"),
- )
- }
-
- @Test
@EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When broadcast flag true and is restore then send installed item broadcast`() {
+ fun `When broadcast flag on and is restore and secure setting off then send new broadcast`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
@@ -417,7 +346,7 @@
)
.thenCallRealMethod()
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
+ Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
// When
LoaderTask(
@@ -436,7 +365,7 @@
@Test
@DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
- fun `When broadcast flag and secure setting false then installed item broadcast not sent`() {
+ fun `When broadcast flag off then installed item broadcast not sent`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
@@ -458,7 +387,57 @@
)
.thenCallRealMethod()
- Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
+ Settings.Secure.putInt(
+ spyContext.contentResolver,
+ "disable_launcher_broadcast_installed_apps",
+ 0,
+ )
+ RestoreDbTask.setPending(spyContext)
+
+ // When
+ LoaderTask(
+ app,
+ bgAllAppsList,
+ BgDataModel(),
+ modelDelegate,
+ launcherBinder,
+ widgetsFilterDataProvider,
+ )
+ .runSyncOnBackgroundThread()
+
+ // Then
+ verify(spyContext, times(0)).sendBroadcast(any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
+ fun `When failsafe secure setting on then installed item broadcast not sent`() {
+ // Given
+ val spyContext = spy(context)
+ `when`(app.context).thenReturn(spyContext)
+ whenever(
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ any(),
+ any(),
+ any(),
+ any(),
+ )
+ )
+ .thenReturn(listOf(expectedBroadcastModel))
+
+ whenever(
+ FirstScreenBroadcastHelper.sendBroadcastsForModels(
+ spyContext,
+ listOf(expectedBroadcastModel),
+ )
+ )
+ .thenCallRealMethod()
+
+ Settings.Secure.putInt(
+ spyContext.contentResolver,
+ "disable_launcher_broadcast_installed_apps",
+ 1,
+ )
RestoreDbTask.setPending(spyContext)
// When
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
index ca2ef42..f381d4b 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
+++ b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
@@ -23,6 +23,7 @@
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.graphics.Bitmap
+import android.os.Process.myUserHandle
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -73,14 +74,14 @@
sessionId = 0
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedVerifiedSession2 =
PackageInstaller.SessionInfo().apply {
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedSessions = listOf(expectedVerifiedSession1, expectedVerifiedSession2)
whenever(launcherApps.allPackageInstallerSessions).thenReturn(expectedSessions)
@@ -97,7 +98,7 @@
PackageInstaller.SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions)
.thenReturn(listOf(expectedVerifiedSession))
@@ -116,7 +117,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(mockPackageInstaller.getSessionInfo(1)).thenReturn(expectedSession)
// When
@@ -147,14 +148,14 @@
sessionId = 0
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedVerifiedSession2 =
PackageInstaller.SessionInfo().apply {
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
val expectedSessions = listOf(expectedVerifiedSession1, expectedVerifiedSession2)
whenever(launcherApps.allPackageInstallerSessions).thenReturn(expectedSessions)
@@ -174,7 +175,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions).thenReturn(listOf(expectedSession))
// When
@@ -196,7 +197,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "app2"
- userId = 0
+ userId = myUserHandle().identifier
}
whenever(launcherApps.allPackageInstallerSessions).thenReturn(listOf(expectedSession))
// When
@@ -219,7 +220,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "appPackage"
- userId = 0
+ userId = myUserHandle().identifier
appIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)
appLabel = "appLabel"
installReason = PackageManager.INSTALL_REASON_USER
@@ -249,7 +250,7 @@
sessionId = 1
installerPackageName = expectedInstallerPackage
appPackageName = "appPackage"
- userId = 0
+ userId = myUserHandle().identifier
appIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)
appLabel = "appLabel"
installReason = PackageManager.INSTALL_REASON_USER