Merge "Refactoring OverviewCommandHelper (1/3)" into main
diff --git a/Android.bp b/Android.bp
index def024e..b205d0c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -27,7 +27,7 @@
"android.os.flags-aconfig-java",
"android.appwidget.flags-aconfig-java",
"com.android.window.flags.window-aconfig-java",
- ]
+ ],
}
// Common source files used to build launcher (java and kotlin)
@@ -153,7 +153,7 @@
soong_config_variables: {
release_enable_compose_in_launcher: {
srcs: [
- ":launcher-compose-enabled-src"
+ ":launcher-compose-enabled-src",
],
// Compose dependencies
@@ -166,7 +166,7 @@
// in compose/launcher3/facade/disabled/.
conditions_default: {
srcs: [
- ":launcher-compose-disabled-src"
+ ":launcher-compose-disabled-src",
],
static_libs: [],
},
@@ -179,7 +179,7 @@
soong_config_variables: {
release_enable_compose_in_launcher: {
srcs: [
- ":launcher-quickstep-compose-enabled-src"
+ ":launcher-quickstep-compose-enabled-src",
],
// Compose dependencies
@@ -192,7 +192,7 @@
// in compose/quickstep/facade/disabled/.
conditions_default: {
srcs: [
- ":launcher-quickstep-compose-disabled-src"
+ ":launcher-quickstep-compose-disabled-src",
],
static_libs: [],
},
@@ -322,6 +322,8 @@
"kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
+ "dagger2",
+ "jsr330",
],
manifest: "AndroidManifest-common.xml",
@@ -357,6 +359,7 @@
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
target_sdk_version: "current",
+ plugins: ["dagger2-compiler"],
privileged: true,
system_ext_specific: true,
@@ -392,6 +395,7 @@
"lottie",
"SystemUISharedLib",
"SettingsLibSettingsTheme",
+ "dagger2",
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
@@ -421,7 +425,10 @@
"QuickstepResLib",
"androidx.room_room-runtime",
],
- plugins: ["androidx.room_room-compiler-plugin"],
+ plugins: [
+ "androidx.room_room-compiler-plugin",
+ "dagger2-compiler",
+ ],
manifest: "quickstep/AndroidManifest.xml",
additional_manifests: [
"go/AndroidManifest.xml",
@@ -437,7 +444,7 @@
name: "Launcher3QuickStepLib",
defaults: [
"launcher_compose_defaults",
- "quickstep_compose_defaults"
+ "quickstep_compose_defaults",
],
srcs: [
":launcher-src",
@@ -458,6 +465,7 @@
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
+ plugins: ["dagger2-compiler"],
min_sdk_version: "current",
// TODO(b/319712088): re-enable use_resource_processor
use_resource_processor: false,
@@ -500,7 +508,6 @@
}
-
// Build rule for Launcher3 Go app with quickstep for Android Go devices.
// Note that the following two rules are exactly same, and should
// eventually be merged into a single target
@@ -540,6 +547,7 @@
include_filter: ["com.android.launcher3.*"],
},
}
+
android_app {
name: "Launcher3QuickStepGo",
static_libs: ["Launcher3GoLib"],
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index dbcf49c..40c3797 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -316,6 +316,7 @@
description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
bug: "355237285"
}
+
flag {
name: "navigate_to_child_preference"
namespace: "launcher"
@@ -349,3 +350,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "ignore_three_finger_trackpad_for_nav_handle_long_press"
+ namespace: "launcher"
+ description: "Ignore three finger trackpad event for nav handle long press"
+ bug: "342143522"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 4a1035f..e51c956 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -65,7 +65,6 @@
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.util.AnimUtils.clampToDuration;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
@@ -1228,9 +1227,7 @@
* Registers remote animations used when closing apps to home screen.
*/
public void registerRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).shareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
@@ -1294,9 +1291,7 @@
}
protected void unregisterRemoteTransitions() {
- if (ENABLE_SHELL_TRANSITIONS) {
- SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
- }
+ SystemUiProxy.INSTANCE.get(mLauncher).unshareTransactionQueue();
if (SEPARATE_RECENTS_ACTIVITY.get()) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index e925af6..50e8e5e 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -20,7 +20,6 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -170,11 +169,6 @@
@Override
protected void registerBackDispatcher() {
- if (!enablePredictiveBackGesture()) {
- super.registerBackDispatcher();
- return;
- }
-
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new BackAnimationCallback());
diff --git a/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java b/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..dab2582
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.dagger;
+
+import dagger.Component;
+
+import javax.inject.Singleton;
+
+/**
+ * Root component for Dagger injection for Launcher Quickstep.
+ */
+@Singleton
+@Component
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+ /** Builder for quickstep LauncherAppComponent. */
+ @Component.Builder
+ interface Builder extends LauncherBaseAppComponent.Builder {
+ LauncherAppComponent build();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 644705b..e31b1d4 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -36,10 +36,10 @@
import com.android.quickstep.GestureState;
import com.android.quickstep.SystemUiProxy;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.util.HashSet;
import java.util.Set;
-import java.util.concurrent.Executor;
/**
* Controls the visibility of the workspace and the resumed / paused state when desktop mode
@@ -51,6 +51,7 @@
private static final boolean DEBUG = false;
private final Launcher mLauncher;
private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
+ private final Set<TaskbarDesktopModeListener> mTaskbarDesktopModeListeners = new HashSet<>();
private int mVisibleDesktopTasksCount;
private boolean mInOverviewState;
@@ -110,6 +111,16 @@
mDesktopVisibilityListeners.remove(listener);
}
+ /** Registers a listener for Taskbar changes in Desktop Mode. */
+ public void registerTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+ mTaskbarDesktopModeListeners.add(listener);
+ }
+
+ /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */
+ public void unregisterTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) {
+ mTaskbarDesktopModeListeners.remove(listener);
+ }
+
/**
* Sets the number of desktop windows that are visible and updates launcher visibility based on
* it.
@@ -201,6 +212,16 @@
DisplayController.handleInfoChangeForDesktopMode(mLauncher);
}
+ private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding="
+ + doesAnyTaskRequireTaskbarRounding);
+ }
+ for (TaskbarDesktopModeListener listener : mTaskbarDesktopModeListeners) {
+ listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding);
+ }
+ }
+
/**
* TODO: b/333533253 - Remove after flag rollout
*/
@@ -377,7 +398,29 @@
@Override
public void onStashedChanged(int displayId, boolean stashed) {
- Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
+ Log.w(TAG, "DesktopTaskListenerImpl: onStashedChanged is deprecated");
}
+
+ @Override
+ public void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding) {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mController != null && DesktopModeStatus.useRoundedCorners()) {
+ Log.d(TAG, "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= "
+ + doesAnyTaskRequireTaskbarRounding);
+ mController.notifyTaskbarDesktopModeListeners(
+ doesAnyTaskRequireTaskbarRounding);
+ }
+ });
+ }
+ }
+
+ /** A listener for Taskbar in Desktop Mode. */
+ public interface TaskbarDesktopModeListener {
+ /**
+ * Callback for when task is resized in desktop mode.
+ *
+ * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
+ */
+ void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 96a6d28..69da7b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.animation.Animator;
@@ -232,9 +231,7 @@
LauncherState state = mLauncher.getStateManager().getState();
boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
&& !state.isTaskbarAlignedWithHotseat(mLauncher);
- if ((ENABLE_SHELL_TRANSITIONS
- && isVisible
- && (nonInteractiveState || mSkipLauncherVisibilityChange))) {
+ if (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
return null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f61840a..a979d58 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -63,7 +63,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.RotateDrawable;
@@ -74,8 +73,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
-import android.view.View.OnClickListener;
-import android.view.View.OnHoverListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
@@ -106,7 +103,6 @@
import com.android.systemui.shared.navigationbar.KeyButtonRipple;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
-import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -304,8 +300,13 @@
.get(ALPHA_INDEX_SMALL_SCREEN),
flags -> (flags & FLAG_SMALL_SCREEN) == 0));
- mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
- .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+ if (!mContext.isPhoneMode()) {
+ mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+ .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+ }
+
+ // Start at 1 because relevant flags are unset at init.
+ mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
// Force nav buttons (specifically back button) to be visible during setup wizard.
boolean isInSetup = !mContext.isUserSetupComplete();
@@ -317,39 +318,41 @@
// - IME is showing (add separate translation for IME)
// - VoiceInteractionWindow (assistant) is showing
// - Keyboard shortcuts helper is showing
- int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
- | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
- mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
- flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
- 1, 0));
- // Center nav buttons in new height for IME.
- float transForIme = (mContext.getDeviceProfile().taskbarHeight
- - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
- // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
- float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
- mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
- flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
- transForIme, defaultButtonTransY));
+ if (!mContext.isPhoneMode()) {
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
+ | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
+ flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+ 1, 0));
+ // Center nav buttons in new height for IME.
+ float transForIme = (mContext.getDeviceProfile().taskbarHeight
+ - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
+ // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+ float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+ mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
+ transForIme, defaultButtonTransY));
- // Start at 1 because relevant flags are unset at init.
- mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
- mPropertyHolders.add(new StatePropertyHolder(
- mOnBackgroundNavButtonColorOverrideMultiplier,
- flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
+ mPropertyHolders.add(new StatePropertyHolder(
+ mOnBackgroundNavButtonColorOverrideMultiplier,
+ flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
- mPropertyHolders.add(new StatePropertyHolder(
- mSlideInViewVisibleNavButtonColorOverride,
- flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ mPropertyHolders.add(new StatePropertyHolder(
+ mSlideInViewVisibleNavButtonColorOverride,
+ flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ }
if (alwaysShowButtons) {
initButtons(mNavButtonContainer, mEndContextualContainer,
mControllers.navButtonController);
updateButtonLayoutSpacing();
- updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneButtonNavMode());
+ updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneMode());
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
- flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+ if (!mContext.isPhoneMode()) {
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
+ flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+ }
} else if (!mIsImeRenderingNavButtons) {
View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mStartContextualContainer, mControllers.navButtonController, R.id.back);
@@ -711,7 +714,7 @@
private void applyState() {
int count = mPropertyHolders.size();
for (int i = 0; i < count; i++) {
- mPropertyHolders.get(i).setState(mState);
+ mPropertyHolders.get(i).setState(mState, mContext.isGestureNav());
}
}
@@ -1177,83 +1180,6 @@
}
}
- private class RotationButtonImpl implements RotationButton {
-
- private final ImageView mButton;
- private AnimatedVectorDrawable mImageDrawable;
-
- RotationButtonImpl(ImageView button) {
- mButton = button;
- }
-
- @Override
- public void setRotationButtonController(RotationButtonController rotationButtonController) {
- // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
- mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
- .getDrawable(rotationButtonController.getIconResId());
- mButton.setImageDrawable(mImageDrawable);
- mButton.setContentDescription(mButton.getResources()
- .getString(R.string.accessibility_rotate_button));
- mImageDrawable.setCallback(mButton);
- }
-
- @Override
- public View getCurrentView() {
- return mButton;
- }
-
- @Override
- public boolean show() {
- mButton.setVisibility(View.VISIBLE);
- mState |= FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean hide() {
- mButton.setVisibility(View.GONE);
- mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean isVisible() {
- return mButton.getVisibility() == View.VISIBLE;
- }
-
- @Override
- public void updateIcon(int lightIconColor, int darkIconColor) {
- // TODO(b/187754252): UI Polish
- }
-
- @Override
- public void setOnClickListener(OnClickListener onClickListener) {
- mButton.setOnClickListener(onClickListener);
- }
-
- @Override
- public void setOnHoverListener(OnHoverListener onHoverListener) {
- mButton.setOnHoverListener(onHoverListener);
- }
-
- @Override
- public AnimatedVectorDrawable getImageDrawable() {
- return mImageDrawable;
- }
-
- @Override
- public void setDarkIntensity(float darkIntensity) {
- // TODO(b/187754252) UI polish
- }
-
- @Override
- public boolean acceptRotationProposal() {
- return mButton.isAttachedToWindow();
- }
- }
-
private static class StatePropertyHolder {
private final float mEnabledValue, mDisabledValue;
@@ -1284,13 +1210,16 @@
mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
}
- public void setState(int flags) {
+ public void setState(int flags, boolean skipAnimation) {
boolean isEnabled = mEnableCondition.test(flags);
if (mIsEnabled != isEnabled) {
mIsEnabled = isEnabled;
mAnimator.cancel();
mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
mAnimator.start();
+ if (skipAnimation) {
+ mAnimator.end();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 487bc54..e19042e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,7 +29,6 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
-import static com.android.launcher3.Flags.enableTaskbarCustomization;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -230,15 +229,12 @@
mNavigationBarPanelContext = navigationBarPanelContext;
applyDeviceProfile(launcherDp);
final Resources resources = getResources();
-
- if (enableTaskbarCustomization()) {
- mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
- mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
- this,
- mTaskbarFeatureEvaluator,
- mDeviceProfile.inv.numRows,
- mDeviceProfile.inv.numColumns);
- }
+ mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
+ mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
+ this,
+ mTaskbarFeatureEvaluator,
+ mDeviceProfile.inv.numRows,
+ mDeviceProfile.inv.numColumns);
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
@@ -348,8 +344,9 @@
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this, () ->
DisplayController.isInDesktopMode(this)),
- bubbleControllersOptional);
-
+ bubbleControllersOptional,
+ new TaskbarDesktopModeController(
+ LauncherActivityInterface.INSTANCE::getDesktopVisibilityController));
mLauncherPrefs = LauncherPrefs.get(this);
}
@@ -1760,12 +1757,10 @@
return mControllers.taskbarStashController.isInStashedLauncherState();
}
- @Nullable
public TaskbarFeatureEvaluator getTaskbarFeatureEvaluator() {
return mTaskbarFeatureEvaluator;
}
- @Nullable
public TaskbarSpecsEvaluator getTaskbarSpecsEvaluator() {
return mTaskbarSpecsEvaluator;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ee64060..4ac7514 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -24,6 +24,7 @@
import android.graphics.Rect
import android.graphics.RectF
import com.android.app.animation.Interpolators
+import com.android.internal.policy.ScreenDecorationsUtils
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapRange
@@ -70,8 +71,8 @@
private var keyShadowDistance = 0f
private var bottomMargin = 0
- private val fullCornerRadius = context.cornerRadius.toFloat()
- private var cornerRadius = fullCornerRadius
+ private val fullCornerRadius: Float
+ private var cornerRadius = 0f
private var widthInsetPercentage = 0f
private val square = Path()
private val circle = Path()
@@ -101,7 +102,14 @@
shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
}
- setCornerRoundness(DEFAULT_ROUNDNESS)
+ if (DisplayController.isInDesktopMode(context)) {
+ fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+ cornerRadius = fullCornerRadius
+ } else {
+ fullCornerRadius = context.cornerRadius.toFloat()
+ cornerRadius = fullCornerRadius
+ setCornerRoundness(MAX_ROUNDNESS)
+ }
}
fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
@@ -273,7 +281,7 @@
}
companion object {
- const val DEFAULT_ROUNDNESS = 1f
+ const val MAX_ROUNDNESS = 1f
private const val DARK_THEME_STROKE_ALPHA = 51
private const val LIGHT_THEME_STROKE_ALPHA = 41
private const val DARK_THEME_SHADOW_ALPHA = 51f
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d94d9175..34ab9f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -25,6 +25,7 @@
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
+import com.android.launcher3.util.DisplayController;
import com.android.systemui.shared.rotation.RotationButtonController;
import java.io.PrintWriter;
@@ -64,6 +65,7 @@
public final KeyboardQuickSwitchController keyboardQuickSwitchController;
public final TaskbarPinningController taskbarPinningController;
public final Optional<BubbleControllers> bubbleControllers;
+ public final TaskbarDesktopModeController taskbarDesktopModeController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -111,7 +113,8 @@
TaskbarEduTooltipController taskbarEduTooltipController,
KeyboardQuickSwitchController keyboardQuickSwitchController,
TaskbarPinningController taskbarPinningController,
- Optional<BubbleControllers> bubbleControllers) {
+ Optional<BubbleControllers> bubbleControllers,
+ TaskbarDesktopModeController taskbarDesktopModeController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -138,6 +141,7 @@
this.keyboardQuickSwitchController = keyboardQuickSwitchController;
this.taskbarPinningController = taskbarPinningController;
this.bubbleControllers = bubbleControllers;
+ this.taskbarDesktopModeController = taskbarDesktopModeController;
}
/**
@@ -173,6 +177,7 @@
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
taskbarPinningController.init(this, mSharedState);
+ taskbarDesktopModeController.init(this, mSharedState);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -188,7 +193,13 @@
taskbarDragLayerController, taskbarScrimViewController,
voiceInteractionWindowController
};
- mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS);
+
+ if (DisplayController.isInDesktopMode(taskbarActivityContext)) {
+ mCornerRoundness.updateValue(taskbarDesktopModeController.getTaskbarCornerRoundness(
+ mSharedState.showCornerRadiusInDesktopMode));
+ } else {
+ mCornerRoundness.updateValue(TaskbarBackgroundRenderer.MAX_ROUNDNESS);
+ }
mAreAllControllersInitialized = true;
for (Runnable postInitCallback : mPostInitCallbacks) {
@@ -248,6 +259,7 @@
keyboardQuickSwitchController.onDestroy();
taskbarStashController.onDestroy();
bubbleControllers.ifPresent(controllers -> controllers.onDestroy());
+ taskbarDesktopModeController.onDestroy();
mControllersToLog = null;
mBackgroundRendererControllers = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
new file mode 100644
index 0000000..a376531
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.taskbar
+
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+
+/** Handles Taskbar in Desktop Windowing mode. */
+class TaskbarDesktopModeController(
+ private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?
+) : TaskbarDesktopModeListener {
+ private lateinit var taskbarControllers: TaskbarControllers
+ private lateinit var taskbarSharedState: TaskbarSharedState
+
+ private val desktopVisibilityController: DesktopVisibilityController?
+ get() = desktopVisibilityControllerProvider()
+
+ fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) {
+ taskbarControllers = controllers
+ taskbarSharedState = sharedState
+ desktopVisibilityController?.registerTaskbarDesktopModeListener(this)
+ }
+
+ override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
+ taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding
+ val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding)
+ taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start()
+ }
+
+ fun getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding: Boolean): Float {
+ return if (doesAnyTaskRequireTaskbarRounding) {
+ MAX_ROUNDNESS
+ } else {
+ 0f
+ }
+ }
+
+ fun onDestroy() = desktopVisibilityController?.unregisterTaskbarDesktopModeListener(this)
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a635537..b5a3314 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -169,8 +169,11 @@
override fun addArrow() {
super.addArrow()
+ val location = IntArray(2)
+ popupContainer.getLocationInDragLayer(dividerView, location)
+ val dividerViewX = location[0].toFloat()
// Change arrow location to the middle of popup.
- mArrow.x = (dividerView.x + dividerView.width / 2) - (mArrowWidth / 2)
+ mArrow.x = (dividerViewX + dividerView.width / 2) - (mArrowWidth / 2)
}
override fun updateArrowColor() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 0eb8890..63fae8c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -48,6 +48,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
@@ -591,6 +592,12 @@
float cornerRoundness = isInLauncher ? 0 : 1;
+ if (DisplayController.isInDesktopMode(mLauncher) && mControllers.getSharedState() != null) {
+ cornerRoundness =
+ mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness(
+ mControllers.getSharedState().showCornerRadiusInDesktopMode);
+ }
+
// Don't animate if corner roundness has reached desired value.
if (mTaskbarCornerRoundness.isAnimating()
|| mTaskbarCornerRoundness.value != cornerRoundness) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 77bd35f..729cbe9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -102,5 +102,8 @@
// To track if taskbar was stashed / unstashed between configuration changes (which recreates
// the task bar).
- public Boolean taskbarWasStashedAuto = true;
+ public boolean taskbarWasStashedAuto = true;
+
+ // should show corner radius on persistent taskbar when in desktop mode.
+ public boolean showCornerRadiusInDesktopMode = false;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 54a7fdc..8b8b4da 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -22,10 +22,8 @@
import static com.android.launcher3.Flags.enableRecentsInTaskbar;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.content.res.Resources;
@@ -39,12 +37,9 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
-import androidx.annotation.DimenRes;
-import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -62,13 +57,12 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.taskbar.customization.TaskbarAllAppsButtonContainer;
+import com.android.launcher3.taskbar.customization.TaskbarDividerContainer;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconButtonView;
-import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.util.AssistStateManager;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
@@ -100,16 +94,13 @@
private View.OnLongClickListener mIconLongClickListener;
// Only non-null when the corresponding Folder is open.
- private @Nullable FolderIcon mLeaveBehindFolderIcon;
+ @Nullable private FolderIcon mLeaveBehindFolderIcon;
// Only non-null when device supports having an All Apps button.
- private @Nullable IconButtonView mAllAppsButton;
- private Runnable mAllAppsTouchRunnable;
- private long mAllAppsButtonTouchDelayMs;
- private boolean mAllAppsTouchTriggered;
+ @Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
- // Only non-null when device supports having an All Apps button, or Recent Apps.
- private @Nullable IconButtonView mTaskbarDivider;
+ // Only non-null when device supports having an All Apps button.
+ @Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
/**
* Whether the divider is between Hotseat icons and Recents,
@@ -173,55 +164,14 @@
// Needed to draw folder leave-behind when opening one.
setWillNotDraw(false);
- mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
- .inflate(R.layout.taskbar_all_apps_button, this, false);
- mAllAppsButton.setIconDrawable(resources.getDrawable(
- getAllAppsButton(isTransientTaskbar)));
- mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
- mAllAppsButton.setForegroundTint(
- mActivityContext.getColor(R.color.all_apps_button_color));
+ mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
- mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
- R.layout.taskbar_divider,
- this, false);
- mTaskbarDivider.setIconDrawable(
- resources.getDrawable(R.drawable.taskbar_divider_button));
- mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ mTaskbarDividerContainer = new TaskbarDividerContainer(context);
}
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
-
- // Default long press (touch) delay = 400ms
- mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
- }
-
- @DrawableRes
- private int getAllAppsButton(boolean isTransientTaskbar) {
- boolean shouldSelectTransientIcon =
- (isTransientTaskbar || enableTaskbarPinning())
- && !mActivityContext.isThreeButtonNav();
- if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- return shouldSelectTransientIcon
- ? R.drawable.ic_transient_taskbar_all_apps_search_button
- : R.drawable.ic_taskbar_all_apps_search_button;
- } else {
- return shouldSelectTransientIcon
- ? R.drawable.ic_transient_taskbar_all_apps_button
- : R.drawable.ic_taskbar_all_apps_button;
- }
- }
-
- @DimenRes
- public int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
- if (isTransientTaskbar) {
- return R.dimen.transient_taskbar_all_apps_button_translation_x_offset;
- } else {
- return ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()
- ? R.dimen.taskbar_all_apps_search_button_translation_x_offset
- : R.dimen.taskbar_all_apps_button_translation_x_offset;
- }
}
@Override
@@ -306,27 +256,11 @@
mIconClickListener = mControllerCallbacks.getIconOnClickListener();
mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnClickListener(this::onAllAppsButtonClick);
- mAllAppsButton.setOnLongClickListener(this::onAllAppsButtonLongClick);
- mAllAppsButton.setOnTouchListener(this::onAllAppsButtonTouch);
- mAllAppsButton.setHapticFeedbackEnabled(
- mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
- mAllAppsTouchRunnable = () -> {
- mControllerCallbacks.triggerAllAppsButtonLongClick();
- mAllAppsTouchTriggered = true;
- };
- AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(mContext);
- if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
- && assistStateManager.getLPNHDurationMillis().isPresent()) {
- mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
- }
+ if (mAllAppsButtonContainer != null) {
+ mAllAppsButtonContainer.setUpCallbacks(callbacks);
}
- if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
- mTaskbarDivider.setOnLongClickListener(
- mControllerCallbacks.getTaskbarDividerLongClickListener());
- mTaskbarDivider.setOnTouchListener(
- mControllerCallbacks.getTaskbarDividerRightClickListener());
+ if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
+ mTaskbarDividerContainer.setUpCallbacks(callbacks);
}
}
@@ -348,11 +282,11 @@
int numViewsAnimated = 0;
mAddedDividerForRecents = false;
- if (mAllAppsButton != null) {
- removeView(mAllAppsButton);
+ if (mAllAppsButtonContainer != null) {
+ removeView(mAllAppsButtonContainer);
- if (mTaskbarDivider != null) {
- removeView(mTaskbarDivider);
+ if (mTaskbarDividerContainer != null) {
+ removeView(mTaskbarDividerContainer);
}
}
removeView(mQsb);
@@ -439,8 +373,8 @@
nextViewIndex++;
}
- if (mTaskbarDivider != null && !recentTasks.isEmpty()) {
- addView(mTaskbarDivider, nextViewIndex++);
+ if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
+ addView(mTaskbarDividerContainer, nextViewIndex++);
mAddedDividerForRecents = true;
}
@@ -504,12 +438,14 @@
removeAndRecycle(getChildAt(nextViewIndex));
}
- if (mAllAppsButton != null) {
- addView(mAllAppsButton, mIsRtl ? hotseatItemInfos.length : 0);
+ if (mAllAppsButtonContainer != null) {
+ addView(mAllAppsButtonContainer, mIsRtl ? hotseatItemInfos.length : 0);
// If there are no recent tasks, add divider after All Apps (unless it's the only view).
- if (!mAddedDividerForRecents && mTaskbarDivider != null && getChildCount() > 1) {
- addView(mTaskbarDivider, mIsRtl ? (getChildCount() - 1) : 1);
+ if (!mAddedDividerForRecents
+ && mTaskbarDividerContainer != null
+ && getChildCount() > 1) {
+ addView(mTaskbarDividerContainer, mIsRtl ? (getChildCount() - 1) : 1);
}
}
if (mActivityContext.getDeviceProfile().isQsbInline) {
@@ -637,7 +573,7 @@
int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2;
int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight;
child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom);
- } else if (child == mTaskbarDivider) {
+ } else if (child == mTaskbarDividerContainer) {
iconEnd += mItemMarginLeftRight;
int iconStart = iconEnd - mIconTouchSize;
child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
@@ -727,16 +663,16 @@
* Returns the all apps button in the taskbar.
*/
@Nullable
- public View getAllAppsButtonView() {
- return mAllAppsButton;
+ public TaskbarAllAppsButtonContainer getAllAppsButtonContainer() {
+ return mAllAppsButtonContainer;
}
/**
* Returns the taskbar divider in the taskbar.
*/
@Nullable
- public View getTaskbarDividerView() {
- return mTaskbarDivider;
+ public TaskbarDividerContainer getTaskbarDividerViewContainer() {
+ return mTaskbarDividerContainer;
}
/**
@@ -832,48 +768,6 @@
}
}
}
- return mAllAppsButton;
- }
-
- private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mAllAppsTouchTriggered = false;
- MAIN_EXECUTOR.getHandler().postDelayed(
- mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- cancelAllAppsButtonTouch();
- }
- return false;
- }
-
- private void cancelAllAppsButtonTouch() {
- MAIN_EXECUTOR.getHandler().removeCallbacks(mAllAppsTouchRunnable);
- // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
- // the next frame, so we need to post twice and delay the reset.
- if (mAllAppsButton != null) {
- mAllAppsButton.post(() -> {
- mAllAppsButton.post(() -> {
- mAllAppsTouchTriggered = false;
- });
- });
- }
- }
-
- private void onAllAppsButtonClick(View view) {
- if (!mAllAppsTouchTriggered) {
- mControllerCallbacks.triggerAllAppsButtonClick(view);
- }
- }
-
- // Handle long click from Switch Access and Voice Access
- private boolean onAllAppsButtonLongClick(View view) {
- if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
- && !mAllAppsTouchTriggered) {
- mControllerCallbacks.triggerAllAppsButtonLongClick();
- }
- return true;
+ return mAllAppsButtonContainer;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index e6cac2f..296d379 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -51,7 +51,7 @@
}
/** Trigger All Apps button click action. */
- protected void triggerAllAppsButtonClick(View v) {
+ public void triggerAllAppsButtonClick(View v) {
InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
/* tag= */ "TASKBAR_BUTTON");
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
@@ -59,7 +59,7 @@
}
/** Trigger All Apps button long click action. */
- protected void triggerAllAppsButtonLongClick() {
+ public void triggerAllAppsButtonLongClick() {
mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
}
@@ -74,6 +74,11 @@
};
}
+ /** Check to see if we support long press on taskbar divider */
+ public boolean supportsDividerLongPress() {
+ return !mActivity.isThreeButtonNav();
+ }
+
public View.OnTouchListener getTaskbarDividerRightClickListener() {
return (v, event) -> {
if (event.isFromSource(InputDevice.SOURCE_MOUSE)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index aef21aa..aa3e6bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -72,7 +72,6 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
@@ -219,8 +218,8 @@
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// This gets modified in NavbarButtonsViewController, but the initial value it reads
// may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
- mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
- .animateToValue(mActivity.isPhoneButtonNavMode() ? 0 : 1).start();
+ mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN).setValue(
+ mActivity.isPhoneMode() ? 0 : 1);
}
if (enableTaskbarPinning()) {
mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
@@ -299,7 +298,7 @@
@Nullable
public View getAllAppsButtonView() {
- return mTaskbarView.getAllAppsButtonView();
+ return mTaskbarView.getAllAppsButtonContainer();
}
public AnimatedFloat getTaskbarIconScaleForStash() {
@@ -366,9 +365,9 @@
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
- mTaskbarView.getAllAppsButtonTranslationXOffset(true));
+ mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(true));
float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
- mTaskbarView.getAllAppsButtonTranslationXOffset(false));
+ mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(false));
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
@@ -383,7 +382,7 @@
}
if (mActivity.isThreeButtonNav()) {
- ((IconButtonView) mTaskbarView.getAllAppsButtonView())
+ mTaskbarView.getAllAppsButtonContainer()
.setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
return;
}
@@ -408,8 +407,8 @@
-finalMarginScale * (iconIndex - halfIconCount));
}
- if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
- ((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
+ if (iconView.equals(mTaskbarView.getAllAppsButtonContainer())) {
+ mTaskbarView.getAllAppsButtonContainer().setTranslationXForTaskbarAllAppsIcon(
allAppIconTranslateRange);
}
}
@@ -537,7 +536,7 @@
}
public View getTaskbarDividerView() {
- return mTaskbarView.getTaskbarDividerView();
+ return mTaskbarView.getTaskbarDividerViewContainer();
}
/**
@@ -753,8 +752,8 @@
int firstRecentTaskIndex = -1;
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
- boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
- boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerView();
+ boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
+ boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
boolean isRecentTask = child.getTag() instanceof GroupTask;
// TODO(b/343522351): show recents on the home screen.
final boolean isRecentsInHotseat = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 90ac872..f5ac66f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar.allapps;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
@@ -193,14 +192,12 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mActivityContext.addOnDeviceProfileChangeListener(this);
- if (enablePredictiveBackGesture()) {
- mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
- mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
- OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
- if (dispatcher != null) {
- dispatcher.registerOnBackInvokedCallback(
- OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
- }
+ mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
+ mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ dispatcher.registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, this);
}
}
@@ -208,13 +205,11 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mActivityContext.removeOnDeviceProfileChangeListener(this);
- if (enablePredictiveBackGesture()) {
- mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
- mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
- OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
- if (dispatcher != null) {
- dispatcher.unregisterOnBackInvokedCallback(this);
- }
+ mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
+ mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
+ OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
+ if (dispatcher != null) {
+ dispatcher.unregisterOnBackInvokedCallback(this);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c458936..71867fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -1473,8 +1473,9 @@
pw.println("BubbleBarView state:");
pw.println(" visibility: " + getVisibility());
pw.println(" alpha: " + getAlpha());
- pw.println(" translation Y: " + getTranslationY());
- pw.println(" bubbles in bar (childCount = " + getChildCount() + ")");
+ pw.println(" translationY: " + getTranslationY());
+ pw.println(" childCount: " + getChildCount());
+ pw.println(" hasOverflow: " + hasOverflow());
for (BubbleView bubbleView: getBubbles()) {
BubbleBarItem bubble = bubbleView.getBubble();
String key = bubble == null ? "null" : bubble.getKey();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 5c1a546..65f857e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -793,6 +793,7 @@
pw.println(" mShouldShowEducation: " + mShouldShowEducation);
pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
+ pw.println(" mOverflowAdded: " + mOverflowAdded);
if (mBarView != null) {
mBarView.dump(pw);
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 7d2d36d..726800c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -18,18 +18,27 @@
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.widget.LinearLayout
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewConfiguration
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.core.view.setPadding
import com.android.launcher3.R
import com.android.launcher3.Utilities.dpToPx
-import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR
+import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarViewCallbacks
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.IconButtonView
+import com.android.quickstep.DeviceConfigWrapper
+import com.android.quickstep.util.AssistStateManager
/** Taskbar all apps button container for customizable taskbar. */
class TaskbarAllAppsButtonContainer
@@ -38,19 +47,21 @@
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
-) : LinearLayout(context, attrs), TaskbarContainer {
+) : IconButtonView(context, attrs), TaskbarContainer {
- private val allAppsButton: IconButtonView =
- LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, this, false)
- as IconButtonView
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+ private var allAppsTouchTriggered = false
+ private var allAppsTouchRunnable: Runnable? = null
+ private var allAppsButtonTouchDelayMs: Long = ViewConfiguration.getLongPressTimeout().toLong()
+ private lateinit var taskbarViewCallbacks: TaskbarViewCallbacks
override val spaceNeeded: Int
get() {
- return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+ return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
}
init {
+ LayoutInflater.from(context).inflate(R.layout.taskbar_all_apps_button, null, false)
setUpIcon()
}
@@ -58,24 +69,39 @@
private fun setUpIcon() {
val drawable =
resources.getDrawable(
- getAllAppsButton(activityContext.taskbarFeatureEvaluator!!.isTransient)
+ getAllAppsButton(activityContext.taskbarFeatureEvaluator.isTransient)
)
- val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+ backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
+ setIconDrawable(drawable)
+ setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+ setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
+ }
- allAppsButton.setIconDrawable(drawable)
- allAppsButton.setPadding(padding)
- allAppsButton.setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
-
- // TODO(b/356465292) : add click listeners in future cl
- addView(allAppsButton)
+ @SuppressLint("ClickableViewAccessibility")
+ fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+ taskbarViewCallbacks = callbacks
+ setOnClickListener(this::onAllAppsButtonClick)
+ setOnLongClickListener(this::onAllAppsButtonLongClick)
+ setOnTouchListener(this::onAllAppsButtonTouch)
+ isHapticFeedbackEnabled = taskbarViewCallbacks.isAllAppsButtonHapticFeedbackEnabled()
+ allAppsTouchRunnable = Runnable {
+ taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+ allAppsTouchTriggered = true
+ }
+ val assistStateManager = AssistStateManager.INSTANCE[mContext]
+ if (
+ DeviceConfigWrapper.get().customLpaaThresholds &&
+ assistStateManager.lpnhDurationMillis.isPresent
+ ) {
+ allAppsButtonTouchDelayMs = assistStateManager.lpnhDurationMillis.get()
+ }
}
@DrawableRes
private fun getAllAppsButton(isTransientTaskbar: Boolean): Int {
val shouldSelectTransientIcon =
- isTransientTaskbar ||
- (FeatureFlags.enableTaskbarPinning() && !activityContext.isThreeButtonNav)
- return if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+ isTransientTaskbar || (enableTaskbarPinning() && !activityContext.isThreeButtonNav)
+ return if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button
else R.drawable.ic_taskbar_all_apps_search_button
} else {
@@ -88,10 +114,43 @@
fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int {
return if (isTransientTaskbar) {
R.dimen.transient_taskbar_all_apps_button_translation_x_offset
- } else if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+ } else if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
R.dimen.taskbar_all_apps_search_button_translation_x_offset
} else {
R.dimen.taskbar_all_apps_button_translation_x_offset
}
}
+
+ private fun onAllAppsButtonTouch(view: View, ev: MotionEvent): Boolean {
+ when (ev.action) {
+ MotionEvent.ACTION_DOWN -> {
+ allAppsTouchTriggered = false
+ MAIN_EXECUTOR.handler.postDelayed(allAppsTouchRunnable!!, allAppsButtonTouchDelayMs)
+ }
+ MotionEvent.ACTION_UP,
+ MotionEvent.ACTION_CANCEL -> cancelAllAppsButtonTouch()
+ }
+ return false
+ }
+
+ private fun cancelAllAppsButtonTouch() {
+ MAIN_EXECUTOR.handler.removeCallbacks(allAppsTouchRunnable!!)
+ // ACTION_UP is first triggered, then click listener / long-click listener is triggered on
+ // the next frame, so we need to post twice and delay the reset.
+ this.post { this.post { allAppsTouchTriggered = false } }
+ }
+
+ private fun onAllAppsButtonClick(view: View) {
+ if (!allAppsTouchTriggered) {
+ taskbarViewCallbacks.triggerAllAppsButtonClick(view)
+ }
+ }
+
+ // Handle long click from Switch Access and Voice Access
+ private fun onAllAppsButtonLongClick(view: View): Boolean {
+ if (!MAIN_EXECUTOR.handler.hasCallbacks(allAppsTouchRunnable!!) && !allAppsTouchTriggered) {
+ taskbarViewCallbacks.triggerAllAppsButtonLongClick()
+ }
+ return true
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index 26e71f7..1fb835a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -18,13 +18,15 @@
import android.annotation.SuppressLint
import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color.TRANSPARENT
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.widget.LinearLayout
import androidx.core.view.setPadding
import com.android.launcher3.R
import com.android.launcher3.Utilities.dpToPx
import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarViewCallbacks
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.IconButtonView
@@ -35,31 +37,30 @@
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
-) : LinearLayout(context, attrs), TaskbarContainer {
-
- private val taskbarDivider: IconButtonView =
- LayoutInflater.from(context).inflate(R.layout.taskbar_divider, this, false)
- as IconButtonView
+) : IconButtonView(context, attrs), TaskbarContainer {
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
override val spaceNeeded: Int
get() {
- return dpToPx(activityContext.taskbarSpecsEvaluator!!.taskbarIconSize.size.toFloat())
+ return dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconSize.size.toFloat())
}
init {
+ LayoutInflater.from(context).inflate(R.layout.taskbar_divider, null, false)
setUpIcon()
}
@SuppressLint("UseCompatLoadingForDrawables")
fun setUpIcon() {
+ backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
- val padding = activityContext.taskbarSpecsEvaluator!!.taskbarIconPadding
+ setIconDrawable(drawable)
+ setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+ }
- taskbarDivider.setIconDrawable(drawable)
- taskbarDivider.setPadding(padding)
-
- // TODO(b/356465292):: add click listeners in future cl
- addView(taskbarDivider)
+ @SuppressLint("ClickableViewAccessibility")
+ fun setUpCallbacks(callbacks: TaskbarViewCallbacks) {
+ setOnLongClickListener(callbacks.taskbarDividerLongClickListener)
+ setOnTouchListener(callbacks.taskbarDividerRightClickListener)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
index 887eb01..6be0828 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt
@@ -19,10 +19,11 @@
/** Taskbar Icon Specs */
object TaskbarIconSpecs {
- val iconSize40dp = TaskbarIconSize(40)
- val iconSize44dp = TaskbarIconSize(44)
- val iconSize48dp = TaskbarIconSize(48)
- val iconSize52dp = TaskbarIconSize(52)
+ // Mapping of visual icon size to icon specs value http://b/235886078
+ val iconSize40dp = TaskbarIconSize(44)
+ val iconSize44dp = TaskbarIconSize(48)
+ val iconSize48dp = TaskbarIconSize(52)
+ val iconSize52dp = TaskbarIconSize(57)
val transientTaskbarIconSizes = arrayOf(iconSize44dp, iconSize48dp, iconSize52dp)
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
index 761b47e..f37b2c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt
@@ -25,14 +25,14 @@
numRows: Int = taskbarActivityContext.deviceProfile.inv.numRows,
numColumns: Int = taskbarActivityContext.deviceProfile.inv.numColumns,
) {
- var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numRows, numColumns)
+ var taskbarIconSize: TaskbarIconSize = getIconSizeByGrid(numColumns, numRows)
// TODO(b/341146605) : initialize it to taskbar container in later cl.
private var taskbarContainer: List<TaskbarContainer> = emptyList()
val taskbarIconPadding: Int =
- if (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size > taskbarIconSize.size) {
- (TaskbarIconSpecs.minimumTaskbarIconTouchSize.size - taskbarIconSize.size) / 2
+ if (TaskbarIconSpecs.iconSize52dp.size > taskbarIconSize.size) {
+ (TaskbarIconSpecs.iconSize52dp.size - taskbarIconSize.size) / 2
} else {
0
}
@@ -44,10 +44,10 @@
TaskbarIconSpecs.defaultPersistentIconMargin
}
- fun getIconSizeByGrid(row: Int, column: Int): TaskbarIconSize {
+ fun getIconSizeByGrid(columns: Int, rows: Int): TaskbarIconSize {
return if (taskbarFeatureEvaluator.isTransient) {
TaskbarIconSpecs.transientTaskbarIconSizeByGridSize.getOrDefault(
- TransientTaskbarIconSizeKey(row, column, taskbarFeatureEvaluator.isLandscape),
+ TransientTaskbarIconSizeKey(columns, rows, taskbarFeatureEvaluator.isLandscape),
TaskbarIconSpecs.defaultTransientIconSize,
)
} else {
@@ -102,6 +102,6 @@
data class TaskbarIconSize(val size: Int)
-data class TransientTaskbarIconSizeKey(val row: Int, val column: Int, val isLandscape: Boolean)
+data class TransientTaskbarIconSizeKey(val columns: Int, val rows: Int, val isLandscape: Boolean)
data class TaskbarIconMarginSize(val size: Int)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 37e0034..4590efe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -379,12 +379,7 @@
}
@Override
- public void setIconVisible(boolean visible) {
- setForceHideRing(!visible);
- super.setIconVisible(visible);
- }
-
- private void setForceHideRing(boolean forceHideRing) {
+ public void setForceHideRing(boolean forceHideRing) {
if (mForceHideRing == forceHideRing) {
return;
}
@@ -417,7 +412,7 @@
private void drawEffect(Canvas canvas) {
// Don't draw ring effect if item is about to be dragged or if the icon is not visible.
- if (mDrawForDrag || !mIsIconVisible) {
+ if (mDrawForDrag || !mIsIconVisible || mForceHideRing) {
return;
}
mIconRingPaint.setColor(RING_SHADOW_COLOR);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 17735e1..55c1885 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -22,7 +22,6 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -499,10 +498,8 @@
boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
if (started) {
DeviceProfile profile = getDeviceProfile();
- boolean willUserBeActive =
- (getActivityFlags() & ACTIVITY_STATE_USER_WILL_BE_ACTIVE) != 0;
boolean visible = (state == NORMAL || state == OVERVIEW)
- && (willUserBeActive || isUserActive())
+ && isUserActive()
&& !profile.isVerticalBarLayout()
&& !mIsOverlayVisible;
SystemUiProxy.INSTANCE.get(this)
@@ -696,9 +693,7 @@
// Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
// work, we must opt-in BEFORE registering back dispatcher. So we need to call
// setEnableOnBackInvokedCallback() before super.onCreate()
- if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
- getApplicationInfo().setEnableOnBackInvokedCallback(true);
- }
+ getApplicationInfo().setEnableOnBackInvokedCallback(true);
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
@@ -910,8 +905,7 @@
// event won't go through ViewRootImpl#InputStage#onProcess.
// So when receive back key, try to do the same check thing in
// ViewRootImpl#NativePreImeInputStage#onProcess
- if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
- || event.getKeyCode() != KeyEvent.KEYCODE_BACK
+ if (event.getKeyCode() != KeyEvent.KEYCODE_BACK
|| event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
return false;
}
@@ -922,10 +916,6 @@
@Override
protected void registerBackDispatcher() {
- if (!enablePredictiveBackGesture()) {
- super.registerBackDispatcher();
- return;
- }
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
new OnBackAnimationCallback() {
@@ -1279,10 +1269,6 @@
return ObjectWrapper.wrap(new Integer(info.id));
}
- public void setHintUserWillBeActive() {
- addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
- }
-
@Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
super.onDisplayInfoChanged(context, info, flags);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 2625646..1ba784b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import android.content.Context;
import android.graphics.Color;
@@ -107,8 +106,7 @@
@Override
public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
- if (ENABLE_SHELL_TRANSITIONS) return false;
- return super.isTaskbarAlignedWithHotseat(launcher);
+ return false;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3d94442..05627be 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -949,7 +949,6 @@
// We will handle the sysui flags based on the centermost task view.
mRecentsAnimationController.setUseLauncherSystemBarFlags(swipeUpThresholdPassed
|| (quickswitchThresholdPassed && centermostTaskFlags != 0));
- mRecentsAnimationController.setSplitScreenMinimized(mContext, swipeUpThresholdPassed);
// Provide a hint to WM the direction that we will be settling in case the animation
// needs to be canceled
mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
@@ -1767,8 +1766,7 @@
private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget,
RecentsOrientedState orientationState) {
- if (runningTaskTarget.rotationChange != 0
- && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ if (runningTaskTarget.rotationChange != 0) {
return Math.abs(runningTaskTarget.rotationChange) == ROTATION_90
? ROTATION_270 : ROTATION_90;
} else {
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 3a8c141..777761b 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -68,8 +68,6 @@
public abstract void onAssistantVisibilityChanged(float assistantVisibility);
- public abstract boolean allowMinimizeSplitScreen();
-
public abstract boolean isResumed();
public abstract boolean isStarted();
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 89fbf4a..94a4527 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -133,12 +133,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- // TODO: Remove this once b/77875376 is fixed
- return false;
- }
-
- @Override
public boolean allowAllAppsFromOverview() {
return false;
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index b564fa7..e9fe2f7 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -271,11 +271,6 @@
}
@Override
- public boolean allowMinimizeSplitScreen() {
- return true;
- }
-
- @Override
public boolean allowAllAppsFromOverview() {
return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
// If floating search bar would not show in overview, don't allow all apps gesture.
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index e17cdcd..485fbaa 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -107,9 +107,6 @@
|| !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
mContainer.getRootView().setForceHideBackArrow(true);
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- mContainer.setHintUserWillBeActive();
- }
if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
return new LauncherHomeAnimationFactory() {
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 84f6b55..a03c0f8 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -37,6 +37,7 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.window.CachedDisplayInfo;
+import com.android.systemui.shared.Flags;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -242,7 +243,8 @@
int rotation = display.rotation;
int touchHeight = mNavBarGesturalHeight;
OrientationRectF orientationRectF = new OrientationRectF(0, 0, size.x, size.y, rotation);
- if (mMode == NavigationMode.NO_BUTTON) {
+ if (mMode == NavigationMode.NO_BUTTON
+ || (mMode == NavigationMode.THREE_BUTTONS && Flags.threeButtonCornerSwipe())) {
orientationRectF.top = orientationRectF.bottom - touchHeight;
updateAssistantRegions(orientationRectF);
} else {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 32e2389..7b9b560 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -54,17 +54,14 @@
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
private final SystemUiProxy mSystemUiProxy;
- private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
private RecentsAnimationController mController;
private boolean mCancelled;
- public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
- boolean allowMinimizeSplitScreen) {
+ public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy) {
mSystemUiProxy = systemUiProxy;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@UiThread
@@ -122,7 +119,7 @@
}
mController = new RecentsAnimationController(animationController,
- mAllowMinimizeSplitScreen, this::onAnimationFinished);
+ this::onAnimationFinished);
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
mController::finishAnimationToApp);
@@ -219,7 +216,6 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationCallbacks:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmCancelled=" + mCancelled);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 1b05e28..adcf4ef 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
import android.content.Context;
@@ -52,21 +51,17 @@
private static final String TAG = "RecentsAnimationController";
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationController> mOnFinishedListener;
- private final boolean mAllowMinimizeSplitScreen;
private boolean mUseLauncherSysBarFlags = false;
- private boolean mSplitScreenMinimized = false;
private boolean mFinishRequested = false;
// Only valid when mFinishRequested == true.
private boolean mFinishTargetIsLauncher;
private RunnableList mPendingFinishCallbacks = new RunnableList();
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
- boolean allowMinimizeSplitScreen,
Consumer<RecentsAnimationController> onFinishedListener) {
mController = controller;
mOnFinishedListener = onFinishedListener;
- mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
/**
@@ -85,34 +80,17 @@
if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
mUseLauncherSysBarFlags = useLauncherSysBarFlags;
UI_HELPER_EXECUTOR.execute(() -> {
- if (!ENABLE_SHELL_TRANSITIONS) {
- mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
- } else {
- try {
- WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
- useLauncherSysBarFlags);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to reach window manager", e);
- }
+ try {
+ WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+ useLauncherSysBarFlags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
}
});
}
}
/**
- * Indicates that the gesture has crossed the window boundary threshold and we should minimize
- * if we are in splitscreen.
- */
- public void setSplitScreenMinimized(Context context, boolean splitScreenMinimized) {
- if (!mAllowMinimizeSplitScreen) {
- return;
- }
- if (mSplitScreenMinimized != splitScreenMinimized) {
- mSplitScreenMinimized = splitScreenMinimized;
- }
- }
-
- /**
* Remove task remote animation target from
* {@link RecentsAnimationCallbacks#onTasksAppeared}}.
*/
@@ -272,9 +250,7 @@
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationController:");
- pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
- pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f902284..5131774 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -74,6 +74,7 @@
import com.android.quickstep.util.GestureExclusionManager;
import com.android.quickstep.util.GestureExclusionManager.ExclusionListener;
import com.android.quickstep.util.NavBarPosition;
+import com.android.systemui.shared.Flags;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -548,6 +549,13 @@
}
/**
+ * @return whether the Assistant gesture can be used in 3 button navigation mode.
+ */
+ public boolean supportsAssistantGestureInButtonNav() {
+ return Flags.threeButtonCornerSwipe();
+ }
+
+ /**
* @param ev An ACTION_DOWN motion event
* @return whether the given motion event can trigger the assistant over the current task.
*/
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index db03dac..a01ceb2 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -43,6 +43,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.recents.data.RecentTasksDataSource;
+import com.android.quickstep.recents.data.TaskVisualsChangeNotifier;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TaskVisualsChangeListener;
@@ -65,7 +66,8 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
- TaskStackChangeListener, TaskVisualsChangeListener, SafeCloseable {
+ TaskStackChangeListener, TaskVisualsChangeListener, TaskVisualsChangeNotifier,
+ SafeCloseable {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
@@ -287,6 +289,7 @@
/**
* Adds a listener for visuals changes
*/
+ @Override
public void addThumbnailChangeListener(TaskVisualsChangeListener listener) {
mThumbnailChangeListeners.add(listener);
}
@@ -294,6 +297,7 @@
/**
* Removes a previously added listener
*/
+ @Override
public void removeThumbnailChangeListener(TaskVisualsChangeListener listener) {
mThumbnailChangeListeners.remove(listener);
}
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 6f1ab7d..80c07196 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -41,6 +41,7 @@
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.systemui.shared.Flags;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -157,7 +158,7 @@
// Register for navigation mode changes
mDisplayController.addChangeListener(this);
DisplayController.Info info = mDisplayController.getInfo();
- onDisplayInfoChangedInternal(info, CHANGE_ALL, info.getNavigationMode().hasGestures);
+ onDisplayInfoChangedInternal(info, CHANGE_ALL, hasGestures(info.getNavigationMode()));
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
mOrientationListener = new OrientationEventListener(mContext) {
@@ -229,7 +230,7 @@
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
*/
public void updateGestureTouchRegions() {
- if (!mMode.hasGestures) {
+ if (!hasGestures(mMode)) {
return;
}
@@ -268,7 +269,7 @@
| CHANGE_SUPPORTED_BOUNDS)) != 0) {
mDisplayRotation = info.rotation;
- if (mMode.hasGestures) {
+ if (hasGestures(mMode)) {
updateGestureTouchRegions();
mOrientationTouchTransformer.createOrAddTouchRegion(info);
mCurrentAppRotation = mDisplayRotation;
@@ -295,9 +296,9 @@
mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
mContext.getResources());
- if (forceRegister || (!mMode.hasGestures && newMode.hasGestures)) {
+ if (forceRegister || (!hasGestures(mMode) && hasGestures(newMode))) {
setupOrientationSwipeHandler();
- } else if (mMode.hasGestures && !newMode.hasGestures) {
+ } else if (hasGestures(mMode) && !hasGestures(newMode)) {
destroyOrientationSwipeHandlerCallback();
}
@@ -399,7 +400,7 @@
}
public int getCurrentActiveRotation() {
- if (!mMode.hasGestures) {
+ if (!hasGestures(mMode)) {
// touch rotation should always match that of display for 3 button
return mDisplayRotation;
}
@@ -416,4 +417,8 @@
public OrientationTouchTransformer getOrientationTouchTransformer() {
return mOrientationTouchTransformer;
}
+
+ private boolean hasGestures(NavigationMode mode) {
+ return mode.hasGestures || (mode == THREE_BUTTONS && Flags.threeButtonCornerSwipe());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 85eea3b..49ec597 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -60,9 +60,8 @@
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
- public static final boolean ENABLE_SHELL_TRANSITIONS = true;
- public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
- && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
+ public static final boolean SHELL_TRANSITIONS_ROTATION =
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
private RecentsAnimationController mController;
@@ -160,8 +159,7 @@
final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
mLastGestureState = gestureState;
- RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
- getSystemUiProxy(), containerInterface.allowMinimizeSplitScreen());
+ RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(getSystemUiProxy());
mCallbacks = newCallbacks;
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
@@ -191,7 +189,7 @@
}
mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets);
- if (ENABLE_SHELL_TRANSITIONS && mTargets.hasRecents
+ if (mTargets.hasRecents
// The filtered (MODE_CLOSING) targets only contain 1 home activity.
&& mTargets.apps.length == 1
&& mTargets.apps[0].windowConfiguration.getActivityType()
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 3c6c3e4..580dcc2 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -27,6 +27,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.recents.data.HighResLoadingStateNotifier;
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource;
import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
import com.android.quickstep.util.TaskKeyCache;
@@ -48,7 +49,7 @@
private final boolean mEnableTaskSnapshotPreloading;
private final Context mContext;
- public static class HighResLoadingState {
+ public static class HighResLoadingState implements HighResLoadingStateNotifier {
private boolean mForceHighResThumbnails;
private boolean mVisible;
private boolean mFlingingFast;
@@ -65,11 +66,13 @@
mForceHighResThumbnails = !supportsLowResThumbnails();
}
- public void addCallback(HighResLoadingStateChangedCallback callback) {
+ @Override
+ public void addCallback(@NonNull HighResLoadingStateChangedCallback callback) {
mCallbacks.add(callback);
}
- public void removeCallback(HighResLoadingStateChangedCallback callback) {
+ @Override
+ public void removeCallback(@NonNull HighResLoadingStateChangedCallback callback) {
mCallbacks.remove(callback);
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 69d1c35..4587bdd 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -89,6 +89,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ConstantItem;
import com.android.launcher3.EncryptionType;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.config.FeatureFlags;
@@ -674,8 +675,9 @@
private void initInputMonitor(String reason) {
disposeEventHandlers("Initializing input monitor due to: " + reason);
- if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get()
- || mTrackpadsConnected.isEmpty())) {
+ if (mDeviceState.isButtonNavMode()
+ && !mDeviceState.supportsAssistantGestureInButtonNav()
+ && (!ENABLE_TRACKPAD_GESTURE.get() || mTrackpadsConnected.isEmpty())) {
return;
}
@@ -857,7 +859,9 @@
.append("); cancelling gesture."),
NAVIGATION_MODE_SWITCHED);
event.setAction(ACTION_CANCEL);
- } else if (mDeviceState.isButtonNavMode() && !isTrackpadMotionEvent(event)) {
+ } else if (mDeviceState.isButtonNavMode()
+ && !mDeviceState.supportsAssistantGestureInButtonNav()
+ && !isTrackpadMotionEvent(event)) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ")
.append("Cannot process input event: ")
.append("using 3-button nav and event is not a trackpad event"));
@@ -909,7 +913,22 @@
if (isInSwipeUpTouchRegion && tac != null) {
tac.closeKeyboardQuickSwitchView();
}
- if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
+ if (mDeviceState.isButtonNavMode()
+ && mDeviceState.supportsAssistantGestureInButtonNav()) {
+ reasonString.append("in three button mode which supports Assistant gesture");
+ // Consume gesture event for Assistant (all other gestures should do nothing).
+ if (mDeviceState.canTriggerAssistantAction(event)) {
+ reasonString.append(" and event can trigger assistant action")
+ .append(", consuming gesture for assistant action");
+ mGestureState =
+ createGestureState(mGestureState, getTrackpadGestureType(event));
+ mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
+ } else {
+ reasonString.append(" but event cannot trigger Assistant")
+ .append(", consuming gesture as no-op");
+ mUncheckedConsumer = InputConsumer.NO_OP;
+ }
+ } else if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
|| isHoverActionWithoutConsumer || isOnBubbles) {
reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion
? "one handed mode is not active and event is in swipe up region"
@@ -931,8 +950,7 @@
: "event is a trackpad multi-finger swipe")
.append(" and event can trigger assistant action")
.append(", consuming gesture for assistant action");
- mGestureState = createGestureState(mGestureState,
- getTrackpadGestureType(event));
+ mGestureState = createGestureState(mGestureState, getTrackpadGestureType(event));
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
// should not interrupt it. QuickSwitch assumes that interruption can only
// happen if the next gesture is also quick switch.
@@ -1193,7 +1211,8 @@
NavHandle navHandle = tac != null ? tac.getNavHandle()
: SystemUiProxy.INSTANCE.get(this);
if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
- && navHandle.canNavHandleBeLongPressed()) {
+ && navHandle.canNavHandleBeLongPressed()
+ && !ignoreThreeFingerTrackpadForNavHandleLongPress(mGestureState)) {
reasonString.append(NEWLINE_PREFIX)
.append(reasonPrefix)
.append(SUBSTRING_PREFIX)
@@ -1289,6 +1308,11 @@
return new CompoundString(NEWLINE_PREFIX).append(substring);
}
+ private boolean ignoreThreeFingerTrackpadForNavHandleLongPress(GestureState gestureState) {
+ return Flags.ignoreThreeFingerTrackpadForNavHandleLongPress()
+ && gestureState.isThreeFingerTrackpadGesture();
+ }
+
private void logInputConsumerSelectionReason(
InputConsumer consumer, CompoundString reasonString) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("setInputConsumer: ")
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
index dbe2068..92031c5 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -45,6 +45,7 @@
private boolean mSwipeUpOnBubbleHandle;
private boolean mPassedTouchSlop;
+ private boolean mStashedOrCollapsedOnDown;
private final int mTouchSlop;
private final PointF mDownPos = new PointF();
@@ -69,13 +70,13 @@
@Override
public void onMotionEvent(MotionEvent ev) {
- final boolean isStashed = mBubbleStashController.isStashed();
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
+ mStashedOrCollapsedOnDown = mBubbleStashController.isStashed() || isCollapsed();
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -89,7 +90,7 @@
if (!mPassedTouchSlop) {
mPassedTouchSlop = Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
}
- if ((isCollapsed() || isStashed) && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
+ if (mStashedOrCollapsedOnDown && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
boolean verticalGesture = Math.abs(dY) > Math.abs(dX);
if (verticalGesture && !mBubbleDragController.isDragging()) {
mSwipeUpOnBubbleHandle = true;
@@ -102,11 +103,10 @@
break;
case MotionEvent.ACTION_UP:
boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForTap;
- if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop) {
+ if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop
+ && mStashedOrCollapsedOnDown) {
// Taps on the handle / collapsed state should open the bar
- if (isStashed || isCollapsed()) {
- mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
- }
+ mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
}
break;
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 14f47d1..b66d4cb 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -24,7 +24,6 @@
import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.animation.Animator;
@@ -212,15 +211,13 @@
// This will come back and cancel the interaction.
startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
mHomeLaunched = true;
- } else if (ENABLE_SHELL_TRANSITIONS) {
- if (mTaskAnimationManager.getCurrentCallbacks() != null) {
- if (mRecentsAnimationController != null) {
- finishRecentsAnimationForShell(dismissTask);
- } else {
- // the transition of recents animation hasn't started, wait for it
- mCancelWhenRecentsStart = true;
- mDismissTask = dismissTask;
- }
+ } else if (mTaskAnimationManager.getCurrentCallbacks() != null) {
+ if (mRecentsAnimationController != null) {
+ finishRecentsAnimationForShell(dismissTask);
+ } else {
+ // the transition of recents animation hasn't started, wait for it
+ mCancelWhenRecentsStart = true;
+ mDismissTask = dismissTask;
}
}
mStateCallback.setState(STATE_HANDLER_INVALIDATED);
diff --git a/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..df546ca
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/HighResLoadingStateNotifier.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+/** Notifies added callbacks that high res state has changed */
+interface HighResLoadingStateNotifier {
+ /** Adds a callback for high res loading state */
+ fun addCallback(callback: HighResLoadingStateChangedCallback)
+
+ /** Removes a callback for high res loading state */
+ fun removeCallback(callback: HighResLoadingStateChangedCallback)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index 4f7a541..9c4248c 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -41,10 +41,4 @@
* populated e.g. icons/thumbnails etc.
*/
fun setVisibleTasks(visibleTaskIdList: List<Int>)
-
- /**
- * Override [ThumbnailData] with a map of taskId to [ThumbnailData]. The override only applies
- * if the tasks are already visible, and will be invalidated when tasks become invisible.
- */
- fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>)
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..6e7789d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangeNotifier.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+/** Notifies added listeners that task visuals have changed */
+interface TaskVisualsChangeNotifier {
+ /** Adds a listener for visuals changes */
+ fun addThumbnailChangeListener(listener: TaskVisualsChangeListener)
+
+ /** Removes a listener for visuals changes */
+ fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
new file mode 100644
index 0000000..a141e89
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.recents.data
+
+import android.os.UserHandle
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.quickstep.util.TaskVisualsChangeListener
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+
+/** Delegates the checking of task visuals (thumbnails, high res changes, icons) */
+interface TaskVisualsChangedDelegate :
+ TaskVisualsChangeListener, HighResLoadingStateChangedCallback {
+ /** Registers a callback for visuals relating to icons */
+ fun registerTaskIconChangedCallback(
+ taskKey: Task.TaskKey,
+ taskIconChangedCallback: TaskIconChangedCallback
+ )
+
+ /** Unregisters a callback for visuals relating to icons */
+ fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey)
+
+ /** Registers a callback for visuals relating to thumbnails */
+ fun registerTaskThumbnailChangedCallback(
+ taskKey: Task.TaskKey,
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ )
+
+ /** Unregisters a callback for visuals relating to thumbnails */
+ fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey)
+
+ /** A callback for task icon changes */
+ interface TaskIconChangedCallback {
+ /** Informs the listener that the task icon has changed */
+ fun onTaskIconChanged()
+ }
+
+ /** A callback for task thumbnail changes */
+ interface TaskThumbnailChangedCallback {
+ /** Informs the listener that the task thumbnail data has changed to [thumbnailData] */
+ fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?)
+
+ /** Informs the listener that the default resolution for loading thumbnails has changed */
+ fun onHighResLoadingStateChanged()
+ }
+}
+
+class TaskVisualsChangedDelegateImpl(
+ private val taskVisualsChangeNotifier: TaskVisualsChangeNotifier,
+ private val highResLoadingStateNotifier: HighResLoadingStateNotifier,
+) : TaskVisualsChangedDelegate {
+ private val taskIconChangedCallbacks =
+ mutableMapOf<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>()
+ private val taskThumbnailChangedCallbacks =
+ mutableMapOf<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>()
+ private var isListening = false
+
+ @Synchronized
+ private fun onCallbackRegistered() {
+ if (isListening) return
+
+ taskVisualsChangeNotifier.addThumbnailChangeListener(this)
+ highResLoadingStateNotifier.addCallback(this)
+ isListening = true
+ }
+
+ @Synchronized
+ private fun onCallbackUnregistered() {
+ if (!isListening) return
+
+ if (taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size == 0) {
+ taskVisualsChangeNotifier.removeThumbnailChangeListener(this)
+ highResLoadingStateNotifier.removeCallback(this)
+ }
+
+ isListening = false
+ }
+
+ override fun onTaskIconChanged(taskId: Int) {
+ taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() }
+ }
+
+ override fun onTaskIconChanged(pkg: String, user: UserHandle) {
+ taskIconChangedCallbacks.values
+ .filter { (taskKey, _) ->
+ pkg == taskKey.packageName && user.identifier == taskKey.userId
+ }
+ .forEach { (_, callback) -> callback.onTaskIconChanged() }
+ }
+
+ override fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData?): Task? {
+ taskThumbnailChangedCallbacks[taskId]?.let { (_, callback) ->
+ callback.onTaskThumbnailChanged(thumbnailData)
+ }
+ return null
+ }
+
+ override fun onHighResLoadingStateChanged(enabled: Boolean) {
+ taskThumbnailChangedCallbacks.values.forEach { (_, callback) ->
+ callback.onHighResLoadingStateChanged()
+ }
+ }
+
+ override fun registerTaskIconChangedCallback(
+ taskKey: Task.TaskKey,
+ taskIconChangedCallback: TaskIconChangedCallback
+ ) {
+ taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
+ onCallbackRegistered()
+ }
+
+ override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) {
+ taskIconChangedCallbacks.remove(taskKey.id)
+ onCallbackUnregistered()
+ }
+
+ override fun registerTaskThumbnailChangedCallback(
+ taskKey: Task.TaskKey,
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ ) {
+ taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
+ onCallbackRegistered()
+ }
+
+ override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) {
+ taskThumbnailChangedCallbacks.remove(taskKey.id)
+ onCallbackUnregistered()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 6f9d157..eb3c2d1 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -18,6 +18,8 @@
import android.graphics.drawable.Drawable
import com.android.launcher3.util.coroutines.DispatcherProvider
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
import com.android.quickstep.util.GroupTask
@@ -26,18 +28,20 @@
import kotlin.coroutines.resume
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
@@ -46,12 +50,12 @@
private val recentsModel: RecentTasksDataSource,
private val taskThumbnailDataSource: TaskThumbnailDataSource,
private val taskIconDataSource: TaskIconDataSource,
+ private val taskVisualsChangedDelegate: TaskVisualsChangedDelegate,
recentsCoroutineScope: CoroutineScope,
private val dispatcherProvider: DispatcherProvider,
) : RecentTasksRepository {
private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
- private val thumbnailOverride = MutableStateFlow(mapOf<Int, ThumbnailData>())
private val taskData =
groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
@@ -85,15 +89,13 @@
.distinctUntilChanged()
private val augmentedTaskData: Flow<List<Task>> =
- combine(taskData, thumbnailQueryResults, iconQueryResults, thumbnailOverride) {
+ combine(taskData, thumbnailQueryResults, iconQueryResults) {
tasks,
thumbnailQueryResults,
- iconQueryResults,
- thumbnailOverride ->
+ iconQueryResults ->
tasks.onEach { task ->
// Add retrieved thumbnails + remove unnecessary thumbnails (e.g. invisible)
- task.thumbnail =
- thumbnailOverride[task.key.id] ?: thumbnailQueryResults[task.key.id]
+ task.thumbnail = thumbnailQueryResults[task.key.id]
// TODO(b/352331675) don't load icons for DesktopTaskView
// Add retrieved icons + remove unnecessary icons
@@ -121,61 +123,76 @@
override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
this.visibleTaskIds.value = visibleTaskIdList.toSet()
- addOrUpdateThumbnailOverride(emptyMap())
- }
-
- override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- this.thumbnailOverride.value =
- this.thumbnailOverride.value
- .toMutableMap()
- .apply { putAll(thumbnailOverride) }
- .filterKeys(this.visibleTaskIds.value::contains)
}
/** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
- private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = flow {
- emit(task.key.id to task.thumbnail)
- val thumbnailDataResult: ThumbnailData? =
- withContext(dispatcherProvider.main) {
- suspendCancellableCoroutine { continuation ->
- val cancellableTask =
- taskThumbnailDataSource.getThumbnailInBackground(task) {
- continuation.resume(it)
- }
- continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest = callbackFlow {
+ trySend(task.key.id to task.thumbnail)
+ trySend(task.key.id to getThumbnailFromDataSource(task))
+
+ val callback =
+ object : TaskThumbnailChangedCallback {
+ override fun onTaskThumbnailChanged(thumbnailData: ThumbnailData?) {
+ trySend(task.key.id to thumbnailData)
+ }
+
+ override fun onHighResLoadingStateChanged() {
+ launch { trySend(task.key.id to getThumbnailFromDataSource(task)) }
}
}
- emit(task.key.id to thumbnailDataResult)
+ taskVisualsChangedDelegate.registerTaskThumbnailChangedCallback(task.key, callback)
+ awaitClose { taskVisualsChangedDelegate.unregisterTaskThumbnailChangedCallback(task.key) }
}
- /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
+ /** Flow wrapper for [TaskIconDataSource.getIconInBackground] api */
private fun getIconDataRequest(task: Task): IconDataRequest =
- flow {
- emit(task.key.id to task.getTaskIconQueryResponse())
- val iconDataResponse: TaskIconQueryResponse? =
- withContext(dispatcherProvider.main) {
- suspendCancellableCoroutine { continuation ->
- val cancellableTask =
- taskIconDataSource.getIconInBackground(task) {
- icon,
- contentDescription,
- title ->
- icon.constantState?.let {
- continuation.resume(
- TaskIconQueryResponse(
- it.newDrawable().mutate(),
- contentDescription,
- title
- )
- )
- }
- }
- continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ callbackFlow {
+ trySend(task.key.id to task.getTaskIconQueryResponse())
+ trySend(task.key.id to getIconFromDataSource(task))
+
+ val callback =
+ object : TaskIconChangedCallback {
+ override fun onTaskIconChanged() {
+ launch { trySend(task.key.id to getIconFromDataSource(task)) }
}
}
- emit(task.key.id to iconDataResponse)
+ taskVisualsChangedDelegate.registerTaskIconChangedCallback(task.key, callback)
+ awaitClose {
+ taskVisualsChangedDelegate.unregisterTaskIconChangedCallback(task.key)
+ }
}
.distinctUntilChanged()
+
+ private suspend fun getThumbnailFromDataSource(task: Task) =
+ withContext(dispatcherProvider.main) {
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskThumbnailDataSource.getThumbnailInBackground(task) {
+ continuation.resume(it)
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ }
+
+ private suspend fun getIconFromDataSource(task: Task) =
+ withContext(dispatcherProvider.main) {
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskIconDataSource.getIconInBackground(task) { icon, contentDescription, title
+ ->
+ icon.constantState?.let {
+ continuation.resume(
+ TaskIconQueryResponse(
+ it.newDrawable().mutate(),
+ contentDescription,
+ title
+ )
+ )
+ }
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ }
}
data class TaskIconQueryResponse(
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index 0b672d1..0a5544f 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -22,6 +22,8 @@
import com.android.launcher3.util.coroutines.ProductionDispatchers
import com.android.quickstep.RecentsModel
import com.android.quickstep.recents.data.RecentTasksRepository
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegateImpl
import com.android.quickstep.recents.data.TasksRepository
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
import com.android.quickstep.recents.usecase.GetThumbnailUseCase
@@ -60,14 +62,22 @@
val recentsCoroutineScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
+ val recentsModel = RecentsModel.INSTANCE.get(appContext)
+ val taskVisualsChangedDelegate =
+ TaskVisualsChangedDelegateImpl(
+ recentsModel,
+ recentsModel.thumbnailCache.highResLoadingState
+ )
+ set(TaskVisualsChangedDelegate::class.java.simpleName, taskVisualsChangedDelegate)
// Create RecentsTaskRepository singleton
val recentTasksRepository: RecentTasksRepository =
- with(RecentsModel.INSTANCE.get(appContext)) {
+ with(recentsModel) {
TasksRepository(
this,
thumbnailCache,
iconCache,
+ taskVisualsChangedDelegate,
recentsCoroutineScope,
ProductionDispatchers
)
@@ -155,6 +165,7 @@
thumbnailCache,
iconCache,
get(),
+ get(),
ProductionDispatchers
)
}
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index b1f46a3..1716f2e 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -58,10 +58,6 @@
recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
}
- fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- recentsTasksRepository.addOrUpdateThumbnailOverride(thumbnailOverride)
- }
-
suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
combine(
updatedThumbnails.map {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index ae6757f..1af12f1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -886,8 +886,7 @@
Log.w(TAG, "Package not found: " + packageName, e);
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
DesktopSplitRecentsAnimationListener listener =
new DesktopSplitRecentsAnimationListener(splitPosition, taskBounds);
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 1c417eb..4c6e4ff 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -84,8 +84,7 @@
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
- SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
- false /* allowMinimizeSplitScreen */);
+ SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()));
SplitWithKeyboardShortcutRecentsAnimationListener listener =
new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop);
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index e5c54bb..c7777d8 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -24,7 +24,6 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
@@ -535,21 +534,12 @@
// If mDrawsBelowRecents is unset, no reordering will be enforced.
if (mDrawsBelowRecents != null) {
- // In legacy transitions, the animation leashes remain in same hierarchy in the
- // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will
- // conflict with layers that WM core positions (ie. the input consumers). For shell
- // transitions, the animation leashes are reparented to an animation container so we
- // can bump layers as needed.
- if (ENABLE_SHELL_TRANSITIONS) {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- // 1000 is an arbitrary number to give room for multiple layers.
- : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
- } else {
- builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
- : 0);
- }
+ // In shell transitions, the animation leashes are reparented to an animation container
+ // so we can bump layers as needed.
+ builder.setLayer(mDrawsBelowRecents
+ ? Integer.MIN_VALUE + app.prefixOrderIndex
+ // 1000 is an arbitrary number to give room for multiple layers.
+ : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
index 66bff73..519ef60 100644
--- a/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskVisualsChangeListener.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
+import android.annotation.NonNull;
import android.os.UserHandle;
import com.android.systemui.shared.recents.model.Task;
@@ -36,7 +37,7 @@
/**
* Called when the icon for a task changes
*/
- default void onTaskIconChanged(String pkg, UserHandle user) {}
+ default void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {}
/**
* Called when the icon for a task changes
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
index 731b008..0ab36c9 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
@@ -257,7 +257,7 @@
task: Task,
appUsageLimitTimeMs: Long,
appRemainingTimeMs: Long
- ): String =
+ ): String? =
if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0)
container
.asContext()
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 4dde635..bdca596 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -123,8 +123,8 @@
@Override
public void onGlobalLayout() {
if (isUninitialized()) return;
- positionViews();
- if (mOnTargetChangeRunnable != null) {
+ boolean positionsChanged = positionViews();
+ if (mOnTargetChangeRunnable != null && positionsChanged) {
mOnTargetChangeRunnable.run();
}
}
@@ -212,21 +212,43 @@
onGlobalLayout();
}
- /** Sets the layout parameters of the floating view and its background view child. */
- private void positionViews() {
+ /**
+ * Sets the layout parameters of the floating view and its background view child.
+ * @return true if any of the views positions change due to this call.
+ */
+ private boolean positionViews() {
+ boolean positionsChanged = false;
+
LayoutParams layoutParams = (LayoutParams) getLayoutParams();
- layoutParams.setMargins(0, 0, 0, 0);
- setLayoutParams(layoutParams);
+
+ if (layoutParams.topMargin != 0 || layoutParams.bottomMargin != 0
+ || layoutParams.rightMargin != 0 || layoutParams.leftMargin != 0) {
+ positionsChanged = true;
+ layoutParams.setMargins(0, 0, 0, 0);
+ setLayoutParams(layoutParams);
+ }
// FloatingWidgetView layout is forced LTR
- mBackgroundView.setTranslationX(mBackgroundPosition.left);
- mBackgroundView.setTranslationY(mBackgroundPosition.top + mIconOffsetY);
+ float targetY = mBackgroundPosition.top + mIconOffsetY;
+ if (mBackgroundView.getTranslationX() != mBackgroundPosition.left
+ || mBackgroundView.getTranslationY() != targetY) {
+ positionsChanged = true;
+ mBackgroundView.setTranslationX(mBackgroundPosition.left);
+ mBackgroundView.setTranslationY(targetY);
+ }
+
LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams();
- backgroundParams.leftMargin = 0;
- backgroundParams.topMargin = 0;
- backgroundParams.width = (int) mBackgroundPosition.width();
- backgroundParams.height = (int) mBackgroundPosition.height();
- mBackgroundView.setLayoutParams(backgroundParams);
+ if (backgroundParams.leftMargin != 0 || backgroundParams.topMargin != 0
+ || backgroundParams.width != Math.round(mBackgroundPosition.width())
+ || backgroundParams.height != Math.round(mBackgroundPosition.height())) {
+ positionsChanged = true;
+
+ backgroundParams.leftMargin = 0;
+ backgroundParams.topMargin = 0;
+ backgroundParams.width = Math.round(mBackgroundPosition.width());
+ backgroundParams.height = Math.round(mBackgroundPosition.height());
+ mBackgroundView.setLayoutParams(backgroundParams);
+ }
if (mForegroundOverlayView != null) {
sTmpMatrix.reset();
@@ -237,8 +259,15 @@
sTmpMatrix.postScale(foregroundScale, foregroundScale);
sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top
+ mIconOffsetY);
- mForegroundOverlayView.setMatrix(sTmpMatrix);
+
+ // We use the animation matrix here, because calling setMatrix on the GhostView
+ // actually sets the animation matrix, not the regular one.
+ if (!sTmpMatrix.equals(mForegroundOverlayView.getAnimationMatrix())) {
+ positionsChanged = true;
+ mForegroundOverlayView.setMatrix(sTmpMatrix);
+ }
}
+ return positionsChanged;
}
private void finish(DragLayer dragLayer) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 69a9690..255619a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1079,7 +1079,6 @@
@Nullable
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
if (enableRefactorTaskThumbnail()) {
- mHelper.onTaskThumbnailChanged(taskId, thumbnailData);
return null;
}
if (mHandleTaskStackChanges) {
@@ -1100,8 +1099,7 @@
}
@Override
- public void onTaskIconChanged(String pkg, UserHandle user) {
- // TODO(b/342560598): Listen in TaskRepository and reload.
+ public void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) {
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView tv = requireTaskViewAt(i);
Task task = tv.getFirstTask();
@@ -2549,7 +2547,6 @@
}
if (enableRefactorTaskThumbnail()) {
- // TODO(b/342560598): Listen in TaskRepository and reload.
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index 5b71da1..f5b2176 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -68,8 +68,4 @@
ViewUtils.postFrameDrawn(taskView, onFinishRunnable)
}
}
-
- fun onTaskThumbnailChanged(taskId: Int, thumbnailData: ThumbnailData) {
- recentsViewModel.addOrUpdateThumbnailOverride(mapOf(taskId to thumbnailData))
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 815f8fa..1f46fa7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -1041,14 +1041,12 @@
// triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
return RunnableList().also { recentsView.addSideTaskLaunchCallback(it) }
}
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- // If the recents transition is running (ie. in live tile mode), then the start
- // of a new task will merge into the existing transition and it currently will
- // not be run independently, so we need to rely on the onTaskAppeared() call
- // for the new task to trigger the side launch callback to flush this runnable
- // list (which is usually flushed when the app launch animation finishes)
- recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
- }
+ // If the recents transition is running (ie. in live tile mode), then the start
+ // of a new task will merge into the existing transition and it currently will
+ // not be run independently, so we need to rely on the onTaskAppeared() call
+ // for the new task to trigger the side launch callback to flush this runnable
+ // list (which is usually flushed when the app launch animation finishes)
+ recentsView.addSideTaskLaunchCallback(opts.onEndCallback)
return opts.onEndCallback
} else {
notifyTaskLaunchFailed()
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
new file mode 100644
index 0000000..72bbfc9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.taskbar
+
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+class TaskbarDesktopModeControllerTest {
+
+ private val context =
+ TaskbarWindowSandboxContext.create(
+ InstrumentationRegistry.getInstrumentation().targetContext
+ )
+
+ @get:Rule(order = 0) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @TaskbarUnitTestRule.InjectController
+ lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
+
+ @Test
+ fun whenTaskbarRequiresCornerRoundness_shouldReturnDefaultCornerRoundness() {
+ assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(true))
+ .isEqualTo(MAX_ROUNDNESS)
+ }
+
+ @Test
+ fun whenTaskbarRequiresCornerRoundness_shouldReturnZeroAsCornerRoundness() {
+ assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(false)).isEqualTo(0f)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
new file mode 100644
index 0000000..7d09efd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeHighResLoadingStateNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback
+
+class FakeHighResLoadingStateNotifier : HighResLoadingStateNotifier {
+ val listeners = mutableListOf<HighResLoadingStateChangedCallback>()
+
+ override fun addCallback(callback: HighResLoadingStateChangedCallback) {
+ listeners.add(callback)
+ }
+
+ override fun removeCallback(callback: HighResLoadingStateChangedCallback) {
+ listeners.remove(callback)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
index fee4979..5de876a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
@@ -27,7 +27,8 @@
class FakeTaskIconDataSource : TaskIconDataSource {
- val taskIdToDrawable: Map<Int, Drawable> = (0..10).associateWith { mockCopyableDrawable() }
+ val taskIdToDrawable: MutableMap<Int, Drawable> =
+ (0..10).associateWith { mockCopyableDrawable() }.toMutableMap()
val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
var shouldLoadSynchronously: Boolean = true
@@ -52,15 +53,17 @@
return null
}
- private fun mockCopyableDrawable(): Drawable {
- val mutableDrawable = mock<Drawable>()
- val immutableDrawable =
- mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
- val constantState =
- mock<Drawable.ConstantState>().apply {
- whenever(newDrawable()).thenReturn(immutableDrawable)
- }
- return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+ companion object {
+ fun mockCopyableDrawable(): Drawable {
+ val mutableDrawable = mock<Drawable>()
+ val immutableDrawable =
+ mock<Drawable>().apply { whenever(mutate()).thenReturn(mutableDrawable) }
+ val constantState =
+ mock<Drawable.ConstantState>().apply {
+ whenever(newDrawable()).thenReturn(immutableDrawable)
+ }
+ return mutableDrawable.apply { whenever(this.constantState).thenReturn(constantState) }
+ }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
index 30fc491..d12c0b0 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -27,7 +27,8 @@
class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
- val taskIdToBitmap: Map<Int, Bitmap> = (0..10).associateWith { mock() }
+ val taskIdToBitmap: MutableMap<Int, Bitmap> =
+ (0..10).associateWith { mock<Bitmap>() }.toMutableMap()
val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
var shouldLoadSynchronously: Boolean = true
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
new file mode 100644
index 0000000..765f0d1
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskVisualsChangeNotifier.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.util.TaskVisualsChangeListener
+
+class FakeTaskVisualsChangeNotifier : TaskVisualsChangeNotifier {
+ val listeners = mutableListOf<TaskVisualsChangeListener>()
+
+ override fun addThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeThumbnailChangeListener(listener: TaskVisualsChangeListener) {
+ listeners.remove(listener)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
index d94a351..7a17872 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -28,7 +28,6 @@
private var taskIconDataMap: Map<Int, TaskIconQueryResponse> = emptyMap()
private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
- private var thumbnailOverrideMap: Map<Int, ThumbnailData> = emptyMap()
override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
@@ -39,7 +38,7 @@
.map { taskList ->
val task = taskList.firstOrNull { it.key.id == taskId } ?: return@map null
Task(task).apply {
- thumbnail = thumbnailOverrideMap[taskId] ?: task.thumbnail
+ thumbnail = task.thumbnail
icon = task.icon
titleDescription = task.titleDescription
title = task.title
@@ -62,16 +61,6 @@
}
}
}
- setThumbnailOverrideInternal(thumbnailOverrideMap)
- }
-
- override fun addOrUpdateThumbnailOverride(thumbnailOverride: Map<Int, ThumbnailData>) {
- setThumbnailOverrideInternal(thumbnailOverride)
- }
-
- private fun setThumbnailOverrideInternal(thumbnailOverride: Map<Int, ThumbnailData>) {
- thumbnailOverrideMap =
- thumbnailOverride.filterKeys(this.visibleTasks.value::contains).toMap()
}
fun seedTasks(tasks: List<Task>) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
new file mode 100644
index 0000000..41f6bfd
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegateTest.kt
@@ -0,0 +1,191 @@
+/*
+ * 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.recents.data
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.UserHandle
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
+import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+class TaskVisualsChangedDelegateTest {
+ private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+ private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+
+ val systemUnderTest =
+ TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
+
+ @Test
+ fun addingFirstListener_addsListenerToNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+
+ assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ }
+
+ @Test
+ fun addingAndRemovingListener_removesListenerFromNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+ systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+ assertThat(taskVisualsChangeNotifier.listeners).isEmpty()
+ assertThat(highResLoadingStateNotifier.listeners).isEmpty()
+ }
+
+ @Test
+ fun addingTwoAndRemovingOneListener_doesNotRemoveListenerFromNotifiers() {
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), mock())
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 2), mock())
+ systemUnderTest.unregisterTaskThumbnailChangedCallback(createTaskKey(id = 1))
+
+ assertThat(taskVisualsChangeNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ assertThat(highResLoadingStateNotifier.listeners.single()).isEqualTo(systemUnderTest)
+ }
+
+ @Test
+ fun onTaskIconChangedWithTaskId_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskIconChangedCallback>()
+ val additionalListener = mock<TaskIconChangedCallback>()
+ systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 1), expectedListener)
+ systemUnderTest.registerTaskIconChangedCallback(createTaskKey(id = 2), additionalListener)
+
+ systemUnderTest.onTaskIconChanged(1)
+
+ verify(expectedListener).onTaskIconChanged()
+ verifyNoMoreInteractions(additionalListener)
+ }
+
+ @Test
+ fun onTaskIconChangedWithoutTaskId_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskIconChangedCallback>()
+ val listener = mock<TaskIconChangedCallback>()
+ // Correct match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ expectedListener
+ )
+ // 1 out of 2 match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 2, pkg = PACKAGE_NAME, userId = 1),
+ listener
+ )
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 3, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 2),
+ listener
+ )
+ // 0 out of 2 match
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 4, pkg = PACKAGE_NAME, userId = 2),
+ listener
+ )
+
+ systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+ verify(expectedListener).onTaskIconChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun replacedTaskIconChangedCallbacks_notCalled() {
+ val replacedListener = mock<TaskIconChangedCallback>()
+ val newListener = mock<TaskIconChangedCallback>()
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ replacedListener
+ )
+ systemUnderTest.registerTaskIconChangedCallback(
+ createTaskKey(id = 1, pkg = ALTERNATIVE_PACKAGE_NAME, userId = 1),
+ newListener
+ )
+
+ systemUnderTest.onTaskIconChanged(ALTERNATIVE_PACKAGE_NAME, UserHandle(1))
+
+ verifyNoMoreInteractions(replacedListener)
+ verify(newListener).onTaskIconChanged()
+ }
+
+ @Test
+ fun onTaskThumbnailChanged_notifiesCorrectListenerOnly() {
+ val expectedListener = mock<TaskThumbnailChangedCallback>()
+ val additionalListener = mock<TaskThumbnailChangedCallback>()
+ val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ expectedListener
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 2),
+ additionalListener
+ )
+
+ systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ verify(expectedListener).onTaskThumbnailChanged(expectedThumbnailData)
+ verifyNoMoreInteractions(additionalListener)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_notifiesAllListeners() {
+ val expectedListener = mock<TaskThumbnailChangedCallback>()
+ val additionalListener = mock<TaskThumbnailChangedCallback>()
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ expectedListener
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 2),
+ additionalListener
+ )
+
+ systemUnderTest.onHighResLoadingStateChanged(true)
+
+ verify(expectedListener).onHighResLoadingStateChanged()
+ verify(additionalListener).onHighResLoadingStateChanged()
+ }
+
+ @Test
+ fun replacedTaskThumbnailChangedCallbacks_notCalled() {
+ val replacedListener1 = mock<TaskThumbnailChangedCallback>()
+ val newListener1 = mock<TaskThumbnailChangedCallback>()
+ val expectedThumbnailData = ThumbnailData(snapshotId = 12345)
+ systemUnderTest.registerTaskThumbnailChangedCallback(
+ createTaskKey(id = 1),
+ replacedListener1
+ )
+ systemUnderTest.registerTaskThumbnailChangedCallback(createTaskKey(id = 1), newListener1)
+
+ systemUnderTest.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ verifyNoMoreInteractions(replacedListener1)
+ verify(newListener1).onTaskThumbnailChanged(expectedThumbnailData)
+ }
+
+ private fun createTaskKey(id: Int = 1, pkg: String = PACKAGE_NAME, userId: Int = 1) =
+ TaskKey(id, 0, Intent().setPackage(pkg), ComponentName("", ""), userId, 0)
+
+ private companion object {
+ const val PACKAGE_NAME = "com.test.test"
+ const val ALTERNATIVE_PACKAGE_NAME = "com.test.test2"
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index e6534eb..f31467f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -19,7 +19,7 @@
import android.content.ComponentName
import android.content.Intent
import android.graphics.Bitmap
-import android.view.Surface
+import android.graphics.drawable.Drawable
import com.android.launcher3.util.TestDispatcherProvider
import com.android.quickstep.task.thumbnail.TaskThumbnailViewModelTest
import com.android.quickstep.util.DesktopTask
@@ -29,6 +29,9 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
@@ -48,6 +51,10 @@
private val recentsModel = FakeRecentTasksDataSource()
private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
private val taskIconDataSource = FakeTaskIconDataSource()
+ private val taskVisualsChangeNotifier = FakeTaskVisualsChangeNotifier()
+ private val highResLoadingStateNotifier = FakeHighResLoadingStateNotifier()
+ private val taskVisualsChangedDelegate =
+ TaskVisualsChangedDelegateImpl(taskVisualsChangeNotifier, highResLoadingStateNotifier)
private val dispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(dispatcher)
@@ -56,6 +63,7 @@
recentsModel,
taskThumbnailDataSource,
taskIconDataSource,
+ taskVisualsChangedDelegate,
testScope.backgroundScope,
TestDispatcherProvider(dispatcher)
)
@@ -203,87 +211,81 @@
}
@Test
- fun addThumbnailOverrideOverrideThumbnails() =
+ fun onTaskThumbnailChanged_setsNewThumbnailDataOnTask() =
testScope.runTest {
recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val thumbnailOverride2 = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
-
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride2.thumbnail)
- }
-
- @Test
- fun addThumbnailOverrideMultipleOverrides() =
- testScope.runTest {
- recentsModel.seedTasks(defaultTaskList)
- val thumbnailOverride1 = createThumbnailData()
- val thumbnailOverride2 = createThumbnailData()
- val thumbnailOverride3 = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride3))
-
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride1.thumbnail)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride3.thumbnail)
- }
-
- @Test
- fun addThumbnailOverrideClearedWhenTaskBecomeInvisible() =
- testScope.runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride1 = createThumbnailData()
- val thumbnailOverride2 = createThumbnailData()
- systemUnderTest.getAllTaskData(forceRefresh = true)
-
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(1 to thumbnailOverride1))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride2))
- // Making task 2 invisible and visible again should clear the override
- systemUnderTest.setVisibleTasks(listOf(1))
- systemUnderTest.setVisibleTasks(listOf(1, 2))
-
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail)
- .isEqualTo(thumbnailOverride1.thumbnail)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
- }
-
- @Test
- fun addThumbnailOverrideDoesNotOverrideInvisibleTasks() =
- testScope.runTest {
- recentsModel.seedTasks(defaultTaskList)
- val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
- val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
- val thumbnailOverride = createThumbnailData()
systemUnderTest.getAllTaskData(forceRefresh = true)
systemUnderTest.setVisibleTasks(listOf(1))
- systemUnderTest.addOrUpdateThumbnailOverride(mapOf(2 to thumbnailOverride))
- systemUnderTest.setVisibleTasks(listOf(1, 2))
- assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
- assertThat(systemUnderTest.getThumbnailById(2).first()!!.thumbnail).isEqualTo(bitmap2)
+ val expectedThumbnailData = createThumbnailData()
+ val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1ThumbnailValues = mutableListOf<ThumbnailData?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail }.toList(task1ThumbnailValues)
+ }
+ taskVisualsChangedDelegate.onTaskThumbnailChanged(1, expectedThumbnailData)
+
+ assertThat(task1ThumbnailValues[1]!!.thumbnail).isEqualTo(expectedPreviousBitmap)
+ assertThat(task1ThumbnailValues.last()).isEqualTo(expectedThumbnailData)
+ }
+
+ @Test
+ fun onHighResLoadingStateChanged_setsNewThumbnailDataOnTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+
+ val expectedBitmap = mock<Bitmap>()
+ val expectedPreviousBitmap = taskThumbnailDataSource.taskIdToBitmap[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1ThumbnailValues = mutableListOf<Bitmap?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.thumbnail?.thumbnail }.toList(task1ThumbnailValues)
+ }
+ taskThumbnailDataSource.taskIdToBitmap[1] = expectedBitmap
+ taskVisualsChangedDelegate.onHighResLoadingStateChanged(true)
+
+ assertThat(task1ThumbnailValues[1]).isEqualTo(expectedPreviousBitmap)
+ assertThat(task1ThumbnailValues.last()).isEqualTo(expectedBitmap)
+ }
+
+ @Test
+ fun onTaskIconChanged_setsNewIconOnTask() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1))
+
+ val expectedIcon = FakeTaskIconDataSource.mockCopyableDrawable()
+ val expectedPreviousIcon = taskIconDataSource.taskIdToDrawable[1]
+ val taskDataFlow = systemUnderTest.getTaskDataById(1)
+
+ val task1IconValues = mutableListOf<Drawable?>()
+ testScope.backgroundScope.launch {
+ taskDataFlow.map { it?.icon }.toList(task1IconValues)
+ }
+ taskIconDataSource.taskIdToDrawable[1] = expectedIcon
+ taskVisualsChangedDelegate.onTaskIconChanged(1)
+
+ assertThat(task1IconValues[1]).isEqualTo(expectedPreviousIcon)
+ assertThat(task1IconValues.last()).isEqualTo(expectedIcon)
}
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
- private fun createThumbnailData(rotation: Int = Surface.ROTATION_0): ThumbnailData {
+ private fun createThumbnailData(): ThumbnailData {
val bitmap = mock<Bitmap>()
whenever(bitmap.width).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_WIDTH)
whenever(bitmap.height).thenReturn(TaskThumbnailViewModelTest.THUMBNAIL_HEIGHT)
- return ThumbnailData(thumbnail = bitmap, rotation = rotation)
+ return ThumbnailData(thumbnail = bitmap)
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
index dc16475..fe67313 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt
@@ -70,44 +70,6 @@
assertThat(thumbnailDataFlow2.first()).isNull()
}
- @Test
- fun thumbnailOverrideWaitAndReset() = runTest {
- val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
- val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
- tasksRepository.seedTasks(tasks)
- tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
-
- val thumbnailDataFlow1 = tasksRepository.getThumbnailById(1)
- val thumbnailDataFlow2 = tasksRepository.getThumbnailById(2)
-
- systemUnderTest.refreshAllTaskData()
- systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
-
- systemUnderTest.setRunningTaskShowScreenshot(true)
- val thumbnailOverride = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
- systemUnderTest.addOrUpdateThumbnailOverride(thumbnailOverride)
-
- systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
- val expectedUpdate = mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
- systemUnderTest.waitForThumbnailsToUpdate(expectedUpdate)
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
-
- systemUnderTest.onReset()
-
- assertThat(thumbnailDataFlow1.first()).isNull()
- assertThat(thumbnailDataFlow2.first()).isNull()
-
- systemUnderTest.updateVisibleTasks(listOf(1, 2))
-
- assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
- assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
- }
-
private fun createTaskWithId(taskId: Int) =
Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
colorBackground = Color.argb(taskId, taskId, taskId, taskId)
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 15b1e53..d064f4a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -57,6 +57,7 @@
@Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
@Mock lateinit var taskbarPinningController: TaskbarPinningController
@Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers>
+ @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController
lateinit var taskbarControllers: TaskbarControllers
@@ -98,6 +99,7 @@
keyboardQuickSwitchController,
taskbarPinningController,
optionalBubbleControllers,
+ taskbarDesktopModeController
)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 597227a..f971afb 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -266,9 +266,6 @@
return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
}
- // Staging; will be promoted to presubmit if stable
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
-
@Test
@NavigationModeSwitch
@PortraitLandscape
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 2c23f86..710ad6f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -16,8 +16,6 @@
package com.android.quickstep;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
import static org.junit.Assert.assertNotNull;
@@ -32,8 +30,6 @@
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
-import com.android.launcher3.util.rule.ScreenRecordRule;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.After;
@@ -95,8 +91,6 @@
@Test
@PortraitLandscape
@NavigationModeSwitch
- @ScreenRecordRule.ScreenRecord // b/336606166
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/336606166
public void switchToOverview() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 3a83ae3..28c8a4a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -59,8 +59,6 @@
@Test
public void startRecentsActivity_allowBackgroundLaunch() {
- assumeTrue(TaskAnimationManager.ENABLE_SHELL_TRANSITIONS);
-
final LauncherActivityInterface activityInterface = mock(LauncherActivityInterface.class);
final GestureState gestureState = mock(GestureState.class);
final RecentsAnimationCallbacks.RecentsAnimationListener listener =
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 633091d..fec94fe 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -110,11 +110,6 @@
public static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 4;
/**
- * State flag indicating if the user will be active shortly.
- */
- public static final int ACTIVITY_STATE_USER_WILL_BE_ACTIVE = 1 << 5;
-
- /**
* State flag indicating that a state transition is in progress
*/
public static final int ACTIVITY_STATE_TRANSITION_ACTIVE = 1 << 6;
@@ -316,7 +311,6 @@
*/
public void setResumed() {
addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
- removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
public boolean isUserActive() {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 26e900d..8121e53 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -89,7 +89,7 @@
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import java.text.NumberFormat;
import java.util.HashMap;
@@ -101,7 +101,7 @@
* too aggressive.
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
- IconLabelDotView, DraggableView, Reorderable {
+ FloatingIconViewCompanion, DraggableView, Reorderable {
public static final String TAG = "BubbleTextView";
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3ca6099..bafb528 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -435,6 +435,10 @@
mIsColdStartupAfterReboot = sIsNewProcess
&& !LockedUserState.get(this).isUserUnlockedAtLauncherStartup();
if (mIsColdStartupAfterReboot) {
+ /*
+ * This trace is used to calculate the time from create to the point that icons are
+ * visible.
+ */
Trace.beginAsyncSection(
COLD_STARTUP_TRACE_METHOD_NAME, COLD_STARTUP_TRACE_COOKIE);
}
@@ -2384,10 +2388,6 @@
.logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
.log()
.reset();
- if (mIsColdStartupAfterReboot) {
- Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
- COLD_STARTUP_TRACE_COOKIE);
- }
});
}
@@ -2396,6 +2396,10 @@
RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
workspaceItemCount, isBindSync);
+ if (mIsColdStartupAfterReboot) {
+ Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
+ COLD_STARTUP_TRACE_COOKIE);
+ }
}
/**
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 40873be..8969b60 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -17,14 +17,23 @@
import android.app.Application;
+import com.android.launcher3.dagger.DaggerLauncherAppComponent;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+
/**
* Main application class for Launcher
*/
public class LauncherApplication extends Application {
+ private LauncherBaseAppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
+ mAppComponent = DaggerLauncherAppComponent.builder().build();
+ }
+
+ public LauncherBaseAppComponent getAppComponent() {
+ return mAppComponent;
}
}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
new file mode 100644
index 0000000..3488c95
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -0,0 +1,32 @@
+/*
+ * 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.dagger;
+
+/**
+ * Launcher base component for Dagger injection.
+ *
+ * This class is not actually annotated as a Dagger component, since it is not used directly as one.
+ * Doing so generates unnecessary code bloat.
+ *
+ * See {@link LauncherAppComponent} for the one actually used by AOSP.
+ */
+public interface LauncherBaseAppComponent {
+ /** Builder for LauncherBaseAppComponent. */
+ interface Builder {
+ LauncherBaseAppComponent build();
+ }
+}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a0b695a..de1bcc3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -83,7 +83,7 @@
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconLabelDotView;
+import com.android.launcher3.views.FloatingIconViewCompanion;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
@@ -93,7 +93,7 @@
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
+public class FolderIcon extends FrameLayout implements FolderListener, FloatingIconViewCompanion,
DraggableView, Reorderable {
private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 84f8049..d2ae93b 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -20,7 +20,7 @@
/**
* Views that contain {@link BubbleTextView} should implement this interface.
*/
-public interface BubbleTextHolder extends IconLabelDotView {
+public interface BubbleTextHolder extends FloatingIconViewCompanion {
BubbleTextView getBubbleText();
@Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 37482ac..4ee6aff 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -22,7 +22,7 @@
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.animation.Animator;
import android.content.Context;
@@ -516,6 +516,10 @@
// When closing an app, we want the item on the workspace to be invisible immediately
updateViewsVisibility(false /* isVisible */);
}
+ if (mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(true);
+ fivc.setForceHideRing(true);
+ }
}
@Override
@@ -653,6 +657,10 @@
if (view.mFadeOutView != null) {
view.mFadeOutView.setAlpha(1f);
}
+ if (view.mFadeOutView instanceof FloatingIconViewCompanion fivc) {
+ fivc.setForceHideDot(false);
+ fivc.setForceHideRing(false);
+ }
if (hideOriginal) {
view.updateViewsVisibility(true /* isVisible */);
@@ -674,10 +682,10 @@
private void updateViewsVisibility(boolean isVisible) {
if (mOriginalIcon != null) {
- setIconAndDotVisible(mOriginalIcon, isVisible);
+ setPropertiesVisible(mOriginalIcon, isVisible);
}
if (mMatchVisibilityView != null) {
- setIconAndDotVisible(mMatchVisibilityView, isVisible);
+ setPropertiesVisible(mMatchVisibilityView, isVisible);
}
}
diff --git a/src/com/android/launcher3/views/FloatingIconViewCompanion.java b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
new file mode 100644
index 0000000..fc23903
--- /dev/null
+++ b/src/com/android/launcher3/views/FloatingIconViewCompanion.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import android.view.View;
+
+/**
+ * A view that can be drawn (in some capacity) via) {@link FloatingIconView}.
+ * This interface allows us to hide certain properties of the view that the FloatingIconView
+ * cannot draw, which allows us to make a seamless handoff between the FloatingIconView and
+ * the companion view.
+ */
+public interface FloatingIconViewCompanion {
+ void setIconVisible(boolean visible);
+ void setForceHideDot(boolean hide);
+ default void setForceHideRing(boolean hide) {}
+
+ /**
+ * Sets the visibility of icon and dot of the view
+ */
+ static void setPropertiesVisible(View view, boolean visible) {
+ if (view instanceof FloatingIconViewCompanion) {
+ ((FloatingIconViewCompanion) view).setIconVisible(visible);
+ ((FloatingIconViewCompanion) view).setForceHideDot(!visible);
+ ((FloatingIconViewCompanion) view).setForceHideRing(!visible);
+ } else {
+ view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index cab7982..7fa7517 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -17,7 +17,7 @@
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
-import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
+import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible;
import android.content.Context;
import android.graphics.Canvas;
@@ -237,7 +237,7 @@
private void setCurrentIconVisible(boolean isVisible) {
if (mIcon != null) {
- setIconAndDotVisible(mIcon, isVisible);
+ setPropertiesVisible(mIcon, isVisible);
}
}
}
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
deleted file mode 100644
index e9113cf..0000000
--- a/src/com/android/launcher3/views/IconLabelDotView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.view.View;
-
-/**
- * A view that has an icon, label, and notification dot.
- */
-public interface IconLabelDotView {
- void setIconVisible(boolean visible);
- void setForceHideDot(boolean hide);
-
- /**
- * Sets the visibility of icon and dot of the view
- */
- static void setIconAndDotVisible(View view, boolean visible) {
- if (view instanceof IconLabelDotView) {
- ((IconLabelDotView) view).setIconVisible(visible);
- ((IconLabelDotView) view).setForceHideDot(!visible);
- } else {
- view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-}
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
new file mode 100644
index 0000000..4d7f937
--- /dev/null
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.dagger;
+
+import dagger.Component;
+
+import javax.inject.Singleton;
+
+/**
+ * Root component for Dagger injection for Launcher AOSP.
+ */
+@Singleton
+@Component
+public interface LauncherAppComponent extends LauncherBaseAppComponent {
+ /** Builder for aosp LauncherAppComponent. */
+ @Component.Builder
+ interface Builder extends LauncherBaseAppComponent.Builder {
+ LauncherAppComponent build();
+ }
+}
+
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 907aa50..7c87c65 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -98,7 +98,6 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/311099513
public void testUninstallFromWorkspace() throws Exception {
installDummyAppAndWaitForUIUpdate();
try {
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 9b184ae..9c916fa 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.ui.widget;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
import static org.junit.Assert.assertNotNull;
import android.platform.test.annotations.PlatinumTest;
@@ -33,7 +30,6 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import org.junit.Assume;
@@ -102,7 +98,6 @@
/**
* Test dragging a widget to the workspace and resize it.
*/
- @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/316910614
@PlatinumTest(focusArea = "launcher")
@Test
public void testResizeWidget() throws Throwable {