Merge "[Contextual Edu] Update Edu stats when going to overview and all apps from home" into main
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index bca7494..5413601 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,7 +20,7 @@
aconfig_declarations {
name: "com_android_launcher3_flags",
package: "com.android.launcher3",
- container: "system_ext",
+ container: "system",
srcs: ["**/*.aconfig"],
}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 3769124..4d6c7ab 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -1,5 +1,5 @@
package: "com.android.launcher3"
-container: "system_ext"
+container: "system"
flag {
name: "enable_expanding_pause_work_button"
@@ -398,3 +398,31 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_dismiss_prediction_undo"
+ namespace: "launcher"
+ description: "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"
+ bug: "270394476"
+}
+
+flag {
+ name: "enable_all_apps_button_in_hotseat"
+ namespace: "launcher"
+ description: "Enables displaying the all apps button in the hotseat."
+ bug: "270393897"
+}
+
+flag {
+ name: "taskbar_quiet_mode_change_support"
+ namespace: "launcher"
+ description: "Support changing quiet mode for user profiles in taskbar."
+ bug: "345760034"
+}
+
+flag {
+ name: "taskbar_overflow"
+ namespace: "launcher"
+ description: "Show recent apps in the taskbar overflow."
+ bug: "368119679"
+}
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 23733a4..853faf8 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -1,5 +1,5 @@
package: "com.android.launcher3"
-container: "system_ext"
+container: "system"
flag {
name: "enable_grid_only_overview"
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index b98eee6..72f654e 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -1,5 +1,5 @@
package: "com.android.launcher3"
-container: "system_ext"
+container: "system"
flag {
name: "enable_private_space"
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
index dab2582..bd6008e 100644
--- a/quickstep/dagger/LauncherAppComponent.java
+++ b/quickstep/dagger/LauncherAppComponent.java
@@ -16,15 +16,16 @@
package com.android.launcher3.dagger;
-import dagger.Component;
-import javax.inject.Singleton;
+import com.android.quickstep.dagger.QuickStepModule;
+
+import dagger.Component;
/**
* Root component for Dagger injection for Launcher Quickstep.
*/
-@Singleton
-@Component
+@LauncherAppSingleton
+@Component(modules = QuickStepModule.class)
public interface LauncherAppComponent extends LauncherBaseAppComponent {
/** Builder for quickstep LauncherAppComponent. */
@Component.Builder
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 685a151..625d9b3 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -96,7 +96,6 @@
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/allset_hint"
android:textSize="@dimen/allset_page_swipe_up_text_size"
android:gravity="center_horizontal"
diff --git a/quickstep/res/layout/bubblebar_flyout.xml b/quickstep/res/layout/bubblebar_flyout.xml
new file mode 100644
index 0000000..ff5047f
--- /dev/null
+++ b/quickstep/res/layout/bubblebar_flyout.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <ImageView
+ android:id="@+id/bubble_flyout_avatar"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:padding="@dimen/bubblebar_flyout_avatar_message_space"
+ android:scaleType="centerInside"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ tools:src="#ff0000"/>
+
+ <TextView
+ android:id="@+id/bubble_flyout_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="1"
+ android:ellipsize="end"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toEndOf="@id/bubble_flyout_avatar"
+ tools:text="Sender"/>
+
+ <TextView
+ android:id="@+id/bubble_flyout_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:maxLines="2"
+ android:ellipsize="end"
+ app:layout_constraintTop_toBottomOf="@id/bubble_flyout_name"
+ app:layout_constraintStart_toEndOf="@id/bubble_flyout_avatar"
+ tools:text="This is a message"/>
+
+</merge>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 4b982ef..21b5fd4 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -97,7 +97,7 @@
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjermbilde"</string>
<string name="action_split" msgid="2098009717623550676">"Del opp"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre app-paret"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string>
<string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index ce3f3ac..e99e9b5 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -350,7 +350,6 @@
<dimen name="taskbar_back_button_left_margin_kids">48dp</dimen>
<dimen name="taskbar_home_button_left_margin_kids">48dp</dimen>
<dimen name="taskbar_icon_size_kids">32dp</dimen>
- <dimen name="taskbar_all_apps_button_translation_x_offset">6dp</dimen>
<dimen name="taskbar_all_apps_search_button_translation_x_offset">6dp</dimen>
<dimen name="taskbar_contextual_button_suw_margin">64dp</dimen>
<dimen name="taskbar_contextual_button_suw_height">64dp</dimen>
@@ -480,6 +479,13 @@
<dimen name="bubble_expanded_view_drop_target_padding">24dp</dimen>
<dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
+ <!-- Bubble bar flyout view -->
+ <dimen name="bubblebar_flyout_padding_horizontal">14dp</dimen>
+ <dimen name="bubblebar_flyout_padding_vertical">10dp</dimen>
+ <dimen name="bubblebar_flyout_elevation">4dp</dimen>
+ <dimen name="bubblebar_flyout_avatar_message_space">6dp</dimen>
+ <dimen name="bubblebar_flyout_max_width">96dp</dimen>
+
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
<!-- starting_surface_exit_animation_window_shift_length -->
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index e940553..a63ba0f 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -26,7 +26,6 @@
import android.animation.AnimatorSet;
import android.content.Context;
import android.os.Handler;
-import android.os.RemoteException;
import android.util.Log;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationTarget;
@@ -210,7 +209,7 @@
* animation finished runnable.
*/
@Override
- public void onAnimationFinished() throws RemoteException {
+ public void onAnimationFinished() {
mASyncFinishRunnable.run();
}
}
@@ -240,12 +239,5 @@
@Override
@UiThread
default void onAnimationCancelled() {}
-
- /**
- * Returns whether this animation factory supports a tightly coupled return animation.
- */
- default boolean supportsReturnTransition() {
- return false;
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2457cfd..a64936d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -51,7 +51,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.mapBoundToRange;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
@@ -111,6 +110,7 @@
import android.view.animation.PathInterpolator;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
+import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -141,6 +141,9 @@
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.AlreadyStartedBackAnimState;
+import com.android.quickstep.util.AnimatorBackState;
+import com.android.quickstep.util.BackAnimState;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
@@ -176,9 +179,6 @@
*/
public class QuickstepTransitionManager implements OnDeviceProfileChangeListener {
- private static final String TRANSITION_COOKIE_PREFIX =
- "com.android.launcher3.QuickstepTransitionManager_activityLaunch";
-
private static final boolean ENABLE_SHELL_STARTING_SURFACE =
SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
@@ -347,14 +347,7 @@
IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback);
options.setOnAnimationAbortListener(endCallback);
options.setOnAnimationFinishedListener(endCallback);
-
- IBinder cookie = mAppLaunchRunner.supportsReturnTransition()
- ? ((ContainerAnimationRunner) mAppLaunchRunner).getCookie() : null;
- addLaunchCookie(cookie, itemInfo, options);
-
- // Register the return animation so it can be triggered on back from the app to home.
- maybeRegisterAppReturnTransition(v);
-
+ options.setLaunchCookie(StableViewInfo.toLaunchCookie(itemInfo));
return new ActivityOptionsWrapper(options, onEndCallback);
}
@@ -367,21 +360,9 @@
ItemInfo tag = (ItemInfo) v.getTag();
ContainerAnimationRunner containerRunner = null;
if (tag != null && tag.shouldUseBackgroundAnimation()) {
- // The cookie should only override the default used by launcher if container return
- // animations are enabled.
- ActivityTransitionAnimator.TransitionCookie cookie =
- checkReturnAnimationsFlags()
- ? new ActivityTransitionAnimator.TransitionCookie(
- TRANSITION_COOKIE_PREFIX + tag.id)
- : null;
- ContainerAnimationRunner launchAnimationRunner =
- ContainerAnimationRunner.fromView(
- v, cookie, true /* forLaunch */, mLauncher, mStartingWindowListener,
- onEndCallback);
-
- if (launchAnimationRunner != null) {
- containerRunner = launchAnimationRunner;
- }
+ containerRunner = ContainerAnimationRunner.fromView(
+ v, true /* forLaunch */, mLauncher, mStartingWindowListener, onEndCallback,
+ null /* windowState */);
}
mAppLaunchRunner = containerRunner != null
@@ -391,51 +372,6 @@
}
/**
- * If container return animations are enabled and the current launch runner is itself a
- * {@link ContainerAnimationRunner}, registers a matching return animation that de-registers
- * itself after it has run once or is made obsolete by the view going away.
- */
- private void maybeRegisterAppReturnTransition(View v) {
- if (!checkReturnAnimationsFlags() || !mAppLaunchRunner.supportsReturnTransition()) {
- return;
- }
-
- ActivityTransitionAnimator.TransitionCookie cookie =
- ((ContainerAnimationRunner) mAppLaunchRunner).getCookie();
- RunnableList onEndCallback = new RunnableList();
- ContainerAnimationRunner runner =
- ContainerAnimationRunner.fromView(
- v, cookie, false /* forLaunch */, mLauncher, mStartingWindowListener,
- onEndCallback);
- RemoteTransition transition =
- new RemoteTransition(
- new LauncherAnimationRunner(
- mHandler, runner, true /* startAtFrontOfQueue */
- ).toRemoteTransition()
- );
-
- SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition(
- transition, ContainerAnimationRunner.buildBackToHomeFilter(cookie, mLauncher));
- ContainerAnimationRunner.setUpRemoteAnimationCleanup(
- v, transition, onEndCallback, mLauncher);
- }
-
- /**
- * Adds a new launch cookie for the activity launch if supported.
- * Prioritizes the explicitly provided cookie, falling back on extracting one from the given
- * {@link ItemInfo} if necessary.
- */
- private void addLaunchCookie(IBinder cookie, ItemInfo info, ActivityOptions options) {
- if (cookie == null) {
- cookie = StableViewInfo.toLaunchCookie(info);
- }
-
- if (cookie != null) {
- options.setLaunchCookie(cookie);
- }
- }
-
- /**
* Whether the launch is a recents app transition and we should do a launch animation
* from the recents view. Note that if the remote animation targets are not provided, this
* may not always be correct as we may resolve the opening app to a task when the animation
@@ -1613,19 +1549,48 @@
* Creates the {@link RectFSpringAnim} and {@link AnimatorSet} required to animate
* the transition.
*/
- public Pair<RectFSpringAnim, AnimatorSet> createWallpaperOpenAnimations(
+ @NonNull
+ public BackAnimState createWallpaperOpenAnimations(
RemoteAnimationTarget[] appTargets,
- RemoteAnimationTarget[] wallpaperTargets,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonAppTargets,
RectF startRect,
float startWindowCornerRadius,
boolean fromPredictiveBack) {
+ View launcherView = findLauncherView(appTargets);
+ if (checkReturnAnimationsFlags()
+ && launcherView != null
+ && launcherView.getTag() instanceof ItemInfo info
+ && info.shouldUseBackgroundAnimation()) {
+ // Try to create a return animation
+ RunnableList onEndCallback = new RunnableList();
+ WindowAnimationState windowState = new WindowAnimationState();
+ windowState.bounds = startRect;
+ windowState.bottomLeftRadius = windowState.bottomRightRadius =
+ windowState.topLeftRadius = windowState.topRightRadius =
+ startWindowCornerRadius;
+ ContainerAnimationRunner runner = ContainerAnimationRunner.fromView(
+ launcherView, false /* forLaunch */, mLauncher, mStartingWindowListener,
+ onEndCallback, windowState);
+ if (runner != null) {
+ runner.startAnimation(TRANSIT_CLOSE,
+ appTargets, wallpapers, nonAppTargets,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() {
+ onEndCallback.executeAllAndDestroy();
+ }
+ });
+ return new AlreadyStartedBackAnimState(onEndCallback);
+ }
+ }
+
AnimatorSet anim = new AnimatorSet();
RectFSpringAnim rectFSpringAnim = null;
final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
|| launcherIsATargetWithMode(appTargets, MODE_OPENING);
- View launcherView = findLauncherView(appTargets);
boolean playFallBackAnimation = (launcherView == null
&& launcherIsForceInvisibleOrOpening)
|| mLauncher.getWorkspace().isOverlayShown()
@@ -1633,7 +1598,7 @@
boolean playWorkspaceReveal = !fromPredictiveBack;
boolean skipAllAppsScale = false;
- if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get() && !playFallBackAnimation) {
+ if (!playFallBackAnimation) {
PointF velocity;
if (enableScalingRevealHomeAnimation()) {
velocity = new PointF();
@@ -1725,7 +1690,7 @@
}
}
- return new Pair(rectFSpringAnim, anim);
+ return new AnimatorBackState(rectFSpringAnim, anim);
}
public static int getTaskbarToHomeDuration() {
@@ -1775,14 +1740,14 @@
}
}
- Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations(
- appTargets, wallpaperTargets, resolveRectF,
+ BackAnimState bankAnimState = createWallpaperOpenAnimations(
+ appTargets, wallpaperTargets, nonAppTargets, resolveRectF,
QuickStepContract.getWindowCornerRadius(mLauncher),
false /* fromPredictiveBack */);
TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, false, null);
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
- result.setAnimation(pair.second, mLauncher);
+ bankAnimState.applyToAnimationResult(result, mLauncher);
}
}
@@ -1850,29 +1815,19 @@
/** The delegate runner that handles the actual animation. */
private final RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> mDelegate;
- @Nullable
- private final ActivityTransitionAnimator.TransitionCookie mCookie;
-
private ContainerAnimationRunner(
- RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate,
- ActivityTransitionAnimator.TransitionCookie cookie) {
+ RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate) {
mDelegate = delegate;
- mCookie = cookie;
- }
-
- @Nullable
- ActivityTransitionAnimator.TransitionCookie getCookie() {
- return mCookie;
}
@Nullable
static ContainerAnimationRunner fromView(
View v,
- ActivityTransitionAnimator.TransitionCookie cookie,
boolean forLaunch,
Launcher launcher,
StartingWindowListener startingWindowListener,
- RunnableList onEndCallback) {
+ RunnableList onEndCallback,
+ @Nullable WindowAnimationState windowState) {
if (!forLaunch && !checkReturnAnimationsFlags()) {
throw new IllegalStateException(
"forLaunch cannot be false when the enableContainerReturnAnimations or "
@@ -1882,7 +1837,7 @@
// First the controller is created. This is used by the runner to animate the
// origin/target view.
ActivityTransitionAnimator.Controller controller =
- buildController(v, cookie, forLaunch);
+ buildController(v, forLaunch, windowState);
if (controller == null) {
return null;
}
@@ -1907,8 +1862,7 @@
return new ContainerAnimationRunner(
new ActivityTransitionAnimator.AnimationDelegate(
- MAIN_EXECUTOR, controller, callback, listener),
- cookie);
+ MAIN_EXECUTOR, controller, callback, listener));
}
/**
@@ -1918,7 +1872,7 @@
*/
@Nullable
private static ActivityTransitionAnimator.Controller buildController(
- View v, ActivityTransitionAnimator.TransitionCookie cookie, boolean isLaunching) {
+ View v, boolean isLaunching, @Nullable WindowAnimationState windowState) {
View viewToUse = findLaunchableViewWithBackground(v);
if (viewToUse == null) {
return null;
@@ -1949,8 +1903,8 @@
@Nullable
@Override
- public ActivityTransitionAnimator.TransitionCookie getTransitionCookie() {
- return cookie;
+ public WindowAnimationState getWindowAnimatorState() {
+ return windowState;
}
};
}
@@ -1964,81 +1918,26 @@
View view) {
View current = view;
while (current.getBackground() == null || !(current instanceof LaunchableView)) {
- if (!(current.getParent() instanceof View)) {
+ if (current.getParent() instanceof View v) {
+ current = v;
+ } else {
return null;
}
-
- current = (View) current.getParent();
}
-
return (T) current;
}
- /**
- * Builds the filter used by WM Shell to match app closing transitions (only back, no home
- * button/gesture) to the given launch cookie.
- */
- static TransitionFilter buildBackToHomeFilter(
- ActivityTransitionAnimator.TransitionCookie cookie, Launcher launcher) {
- // Closing activity must include the cookie in its list of launch cookies.
- TransitionFilter.Requirement appRequirement = new TransitionFilter.Requirement();
- appRequirement.mActivityType = ACTIVITY_TYPE_STANDARD;
- appRequirement.mLaunchCookie = cookie;
- appRequirement.mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- // Opening activity must be Launcher.
- TransitionFilter.Requirement launcherRequirement = new TransitionFilter.Requirement();
- launcherRequirement.mActivityType = ACTIVITY_TYPE_HOME;
- launcherRequirement.mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- launcherRequirement.mTopActivity = launcher.getComponentName();
- // Transition types CLOSE and TO_BACK match the back button/gesture but not the home
- // button/gesture.
- TransitionFilter filter = new TransitionFilter();
- filter.mTypeSet = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- filter.mRequirements =
- new TransitionFilter.Requirement[]{appRequirement, launcherRequirement};
- return filter;
- }
-
- /**
- * Creates various conditions to ensure that the given transition is cleaned up correctly
- * when necessary:
- * - if the transition has run, it is the callback that unregisters it;
- * - if the associated view is detached before the transition has had an opportunity to run,
- * a {@link View.OnAttachStateChangeListener} allows us to do the same (and removes
- * itself).
- */
- static void setUpRemoteAnimationCleanup(
- View v, RemoteTransition transition, RunnableList callback, Launcher launcher) {
- View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(@NonNull View v) {}
-
- @Override
- public void onViewDetachedFromWindow(@NonNull View v) {
- SystemUiProxy.INSTANCE.get(launcher)
- .unregisterRemoteTransition(transition);
- v.removeOnAttachStateChangeListener(this);
- }
- };
-
- // Remove the animation as soon as it has run once.
- callback.add(() -> {
- SystemUiProxy.INSTANCE.get(launcher).unregisterRemoteTransition(transition);
- if (v != null) {
- v.removeOnAttachStateChangeListener(listener);
- }
- });
-
- // Remove the animation when the view is detached from the hierarchy.
- // This is so that if back is not invoked (e.g. if we go back home through the home
- // gesture) we don't have obsolete transitions staying registered.
- v.addOnAttachStateChangeListener(listener);
- }
-
@Override
public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
LauncherAnimationRunner.AnimationResult result) {
+ startAnimation(
+ transit, appTargets, wallpaperTargets, nonAppTargets, result);
+ }
+
+ public void startAnimation(int transit, RemoteAnimationTarget[] appTargets,
+ RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
+ IRemoteAnimationFinishedCallback result) {
mDelegate.onAnimationStart(
transit, appTargets, wallpaperTargets, nonAppTargets, result);
}
@@ -2047,11 +1946,6 @@
public void onAnimationCancelled() {
mDelegate.onAnimationCancelled();
}
-
- @Override
- public boolean supportsReturnTransition() {
- return true;
- }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 5513599..aa8cea5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -50,6 +50,7 @@
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -135,11 +136,6 @@
mHomeState.removeListener(mVisibilityChangeListener);
}
- /** Returns {@code true} if launcher is currently presenting the home screen. */
- public boolean isOnHome() {
- return mTaskbarLauncherStateController.isOnHome();
- }
-
private void onInAppDisplayProgressChanged() {
if (mControllers != null) {
// Update our shared state so we can restore it if taskbar gets recreated.
@@ -163,6 +159,16 @@
shouldDelayLauncherStateAnim);
}
+ @Override
+ public void stashHotseat(boolean stash) {
+ mTaskbarLauncherStateController.stashHotseat(stash);
+ }
+
+ @Override
+ public void unStashHotseatInstantly() {
+ mTaskbarLauncherStateController.unStashHotseatInstantly();
+ }
+
/**
* Adds the Launcher resume animator to the given animator set.
*
@@ -205,6 +211,9 @@
*/
@Override
public void onLauncherVisibilityChanged(boolean isVisible) {
+ if (DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(mLauncher)) {
+ DisplayController.handleInfoChangeForLauncherVisibilityChanged(mLauncher);
+ }
onLauncherVisibilityChanged(isVisible, false /* fromInit */);
}
@@ -476,4 +485,13 @@
protected String getTaskbarUIControllerName() {
return "LauncherTaskbarUIController";
}
+
+ @Override
+ public void onSwipeToUnstashTaskbar() {
+ // Once taskbar is unstashed, the user cannot return back to the overlay. We can
+ // clear it here to set the expected state once the user goes home.
+ if (mLauncher.getWorkspace().isOverlayShown()) {
+ mLauncher.getWorkspace().onOverlayScrollChanged(0);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index a979d58..e9bd30a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -91,6 +91,7 @@
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
+import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
@@ -106,6 +107,7 @@
import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,7 +117,8 @@
/**
* Controller for managing nav bar buttons in taskbar
*/
-public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController {
+public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController,
+ BubbleBarController.BubbleBarLocationListener {
private final Rect mTempRect = new Rect();
@@ -397,6 +400,12 @@
}
};
mSeparateWindowParent.recreateControllers();
+ if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent()) {
+ BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
+ .bubbleBarViewController.getBubbleBarLocation();
+ onBubbleBarLocationUpdated(bubblesLocation);
+ }
}
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
@@ -1168,6 +1177,52 @@
mHitboxExtender.onAnimationProgressToOverview(alignment);
}
+ /** Adjusts navigation buttons layout accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
+ mNavButtonContainer.setTranslationX(getNavBarTranslationX(location));
+ }
+
+ /** Animates navigation buttons accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationAnimated(BubbleBarLocation location) {
+ // TODO(b/346381754) add the teleport animation similarly to the bubble bar
+ mNavButtonContainer.setTranslationX(getNavBarTranslationX(location));
+ }
+
+ private int getNavBarTranslationX(BubbleBarLocation location) {
+ boolean isNavbarOnRight = location.isOnLeft(mNavButtonsView.isLayoutRtl());
+ DeviceProfile dp = mContext.getDeviceProfile();
+ float navBarTargetStartX;
+ if (mContext.shouldStartAlignTaskbar()) {
+ int navBarSpacing = dp.inlineNavButtonsEndSpacingPx;
+ // If the taskbar is start aligned the navigation bar is aligned to the start or end of
+ // the container, depending on the bubble bar location
+ if (isNavbarOnRight) {
+ navBarTargetStartX = dp.widthPx - navBarSpacing - mNavButtonContainer.getWidth();
+ } else {
+ navBarTargetStartX = navBarSpacing;
+ }
+ } else {
+ // If the task bar is not start aligned, the navigation bar is located in the center
+ // between the taskbar and screen edges, depending on the bubble bar location.
+ float navbarWidth = mNavButtonContainer.getWidth();
+ Rect taskbarBounds = mControllers.taskbarViewController.getIconLayoutBounds();
+ if (isNavbarOnRight) {
+ if (mNavButtonsView.isLayoutRtl()) {
+ float taskBarEnd = taskbarBounds.right;
+ navBarTargetStartX = (dp.widthPx + taskBarEnd - navbarWidth) / 2;
+ } else {
+ navBarTargetStartX = mNavButtonContainer.getLeft();
+ }
+ } else {
+ float taskBarStart = taskbarBounds.left;
+ navBarTargetStartX = (taskBarStart - navbarWidth) / 2;
+ }
+ }
+ return (int) navBarTargetStartX - mNavButtonContainer.getLeft();
+ }
+
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
@Override
public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0efa949..b95c406 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -37,6 +37,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
+import static com.android.launcher3.taskbar.TaskbarStashController.SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
@@ -687,6 +688,11 @@
return mNavMode == NavigationMode.THREE_BUTTONS;
}
+ /** Returns whether taskbar should start align. */
+ public boolean shouldStartAlignTaskbar() {
+ return isThreeButtonNav() && mDeviceProfile.startAlignTaskbar;
+ }
+
public boolean isGestureNav() {
return mNavMode == NavigationMode.NO_BUTTON;
}
@@ -1550,10 +1556,14 @@
/**
* Called when we want to unstash taskbar when user performs swipes up gesture.
+ * @param delayTaskbarBackground whether we will delay the taskbar background animation
*/
- public void onSwipeToUnstashTaskbar() {
+ public void onSwipeToUnstashTaskbar(boolean delayTaskbarBackground) {
+ mControllers.uiController.onSwipeToUnstashTaskbar();
+
boolean wasStashed = mControllers.taskbarStashController.isStashed();
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false,
+ SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE, delayTaskbarBackground);
boolean isStashed = mControllers.taskbarStashController.isStashed();
if (isStashed != wasStashed) {
VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
@@ -1687,7 +1697,7 @@
duration);
View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
- if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
+ if (allAppsButton != null && !FeatureFlags.enableAllAppsButtonInHotseat()) {
ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1);
alphaOverride.setDuration(duration);
alphaOverride.addUpdateListener(a -> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 221504d..685c109 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -147,7 +147,11 @@
defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
}
}
- if (taskbarStashController.isInApp || taskbarStashController.isInOverview) {
+ if (
+ taskbarStashController.isInApp ||
+ taskbarStashController.isInOverview ||
+ DisplayController.showLockedTaskbarOnHome(context)
+ ) {
// only add the taskbar touch region if not on home
val bottom = windowLayoutParams.height
val top = bottom - taskbarTouchableHeight
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 6c6bd71..e301dc4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -16,9 +16,13 @@
package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT;
+import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_FOR_BUBBLES;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -40,6 +44,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Hotseat.HotseatQsbAlphaId;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.Utilities;
@@ -48,6 +53,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;
@@ -144,7 +150,7 @@
private AnimatedFloat mTaskbarBackgroundAlpha;
private AnimatedFloat mTaskbarAlpha;
private AnimatedFloat mTaskbarCornerRoundness;
- private MultiProperty mIconAlphaForHome;
+ private MultiProperty mTaskbarAlphaForHome;
private QuickstepLauncher mLauncher;
private boolean mIsDestroyed = false;
@@ -174,11 +180,11 @@
if (mIsQsbInline && !dp.isQsbInline) {
// We only modify QSB alpha if isQsbInline = true. If we switch to a DP
// where isQsbInline = false, then we need to reset the alpha.
- mLauncher.getHotseat().setQsbAlpha(1f);
+ mLauncher.getHotseat().setQsbAlpha(1f, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
}
mIsQsbInline = dp.isQsbInline;
TaskbarLauncherStateController.this.updateIconAlphaForHome(
- mIconAlphaForHome.getValue());
+ mTaskbarAlphaForHome.getValue(), ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
}
};
@@ -241,7 +247,7 @@
.getTaskbarBackgroundAlpha();
mTaskbarAlpha = mControllers.taskbarDragLayerController.getTaskbarAlpha();
mTaskbarCornerRoundness = mControllers.getTaskbarCornerRoundness();
- mIconAlphaForHome = mControllers.taskbarViewController
+ mTaskbarAlphaForHome = mControllers.taskbarViewController
.getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
resetIconAlignment();
@@ -265,7 +271,7 @@
mIconAlignment.finishAnimation();
- mLauncher.getHotseat().setIconsAlpha(1f);
+ mLauncher.getHotseat().setIconsAlpha(1f, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
mLauncher.getStateManager().removeStateListener(mStateListener);
mCanSyncViews = !mControllers.taskbarActivityContext.isPhoneMode();
@@ -440,11 +446,6 @@
return animator;
}
- /** Returns {@code true} if launcher is currently presenting the home screen. */
- public boolean isOnHome() {
- return isInLauncher() && mLauncherState == LauncherState.NORMAL;
- }
-
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
final boolean isInLauncher = isInLauncher();
final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
@@ -456,9 +457,11 @@
+ ", toAlignment: " + toAlignment);
}
mControllers.bubbleControllers.ifPresent(controllers -> {
- // Show the bubble bar when on launcher home or in overview.
+ // Show the bubble bar when on launcher home (hotseat icons visible) or in overview
boolean onOverview = mLauncherState == LauncherState.OVERVIEW;
- controllers.bubbleStashController.setBubblesShowingOnHome(isOnHome());
+ boolean hotseatIconsVisible = isInLauncher && mLauncherState.areElementsVisible(
+ mLauncher, HOTSEAT_ICONS);
+ controllers.bubbleStashController.setBubblesShowingOnHome(hotseatIconsVisible);
controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview);
});
@@ -660,6 +663,9 @@
* This refers to the intended state - a transition to this state might be in progress.
*/
public boolean isTaskbarAlignedWithHotseat() {
+ if (DisplayController.showLockedTaskbarOnHome(mLauncher) && isInLauncher()) {
+ return false;
+ }
return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
}
@@ -671,8 +677,7 @@
boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
boolean willStashVisually = isInStashedState
&& mControllers.taskbarStashController.supportsVisualStashing();
- boolean isTaskbarAlignedWithHotseat =
- mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
+ boolean isTaskbarAlignedWithHotseat = isTaskbarAlignedWithHotseat();
return isTaskbarAlignedWithHotseat && !willStashVisually;
} else {
return false;
@@ -703,14 +708,17 @@
public void onAnimationEnd(Animator animation) {
if (isInStashedState && committed) {
// Reset hotseat alpha to default
- mLauncher.getHotseat().setIconsAlpha(1);
+ mLauncher.getHotseat().setIconsAlpha(1, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
}
}
@Override
public void onAnimationStart(Animator animation) {
- if (mLauncher.getHotseat().getIconsAlpha() > 0) {
- updateIconAlphaForHome(mLauncher.getHotseat().getIconsAlpha());
+ float hotseatIconsAlpha = mLauncher.getHotseat()
+ .getIconsAlpha(ALPHA_CHANNEL_TASKBAR_ALIGNMENT)
+ .getValue();
+ if (hotseatIconsAlpha > 0) {
+ updateIconAlphaForHome(hotseatIconsAlpha, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
}
}
});
@@ -739,6 +747,33 @@
}
}
+ protected void stashHotseat(boolean stash) {
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_STASHED_FOR_BUBBLES, stash);
+ Runnable swapHotseatWithTaskbar = new Runnable() {
+ @Override
+ public void run() {
+ updateIconAlphaForHome(stash ? 1 : 0, ALPHA_CHANNEL_TASKBAR_STASH);
+ }
+ };
+ if (stash) {
+ stashController.applyState();
+ // if we stashing the hotseat we need to immediately swap it with the animating taskbar
+ swapHotseatWithTaskbar.run();
+ } else {
+ // if we revert stashing make swap after taskbar animation is complete
+ stashController.applyState(/* postApplyAction = */ swapHotseatWithTaskbar);
+ }
+ }
+
+ protected void unStashHotseatInstantly() {
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_STASHED_FOR_BUBBLES, false);
+ stashController.applyState(/* duration = */ 0);
+ updateIconAlphaForHome(/* taskbarAlpha = */ 0,
+ ALPHA_CHANNEL_TASKBAR_STASH, /* updateTaskbarAlpha = */ false);
+ }
+
/**
* Resets and updates the icon alignment.
*/
@@ -748,7 +783,7 @@
}
private void onIconAlignmentRatioChanged() {
- float currentValue = mIconAlphaForHome.getValue();
+ float currentValue = mTaskbarAlphaForHome.getValue();
boolean taskbarWillBeVisible = mIconAlignment.value < 1;
boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0)
|| (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
@@ -756,8 +791,10 @@
mControllers.taskbarViewController.setLauncherIconAlignment(
mIconAlignment.value, mLauncher.getDeviceProfile());
mControllers.navbarButtonsViewController.updateTaskbarAlignment(mIconAlignment.value);
- // Switch taskbar and hotseat in last frame
- updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0);
+ // Switch taskbar and hotseat in last frame and if taskbar is not hidden for bubbles
+ boolean isHiddenForBubbles = mControllers.taskbarStashController.isHiddenForBubbles();
+ updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0, ALPHA_CHANNEL_TASKBAR_ALIGNMENT,
+ /* updateTaskbarAlpha = */ !isHiddenForBubbles);
// Sync the first frame where we swap taskbar and hotseat.
if (firstFrameVisChanged && mCanSyncViews && !Utilities.isRunningInTestHarness()) {
@@ -767,12 +804,20 @@
}
}
- private void updateIconAlphaForHome(float alpha) {
+ private void updateIconAlphaForHome(float taskbarAlpha, @HotseatQsbAlphaId int alphaChannel) {
+ updateIconAlphaForHome(taskbarAlpha, alphaChannel, /* updateTaskbarAlpha = */ true);
+ }
+
+ private void updateIconAlphaForHome(float taskbarAlpha,
+ @HotseatQsbAlphaId int alphaChannel,
+ boolean updateTaskbarAlpha) {
if (mIsDestroyed) {
return;
}
- mIconAlphaForHome.setValue(alpha);
- boolean hotseatVisible = alpha == 0
+ if (updateTaskbarAlpha) {
+ mTaskbarAlphaForHome.setValue(taskbarAlpha);
+ }
+ boolean hotseatVisible = taskbarAlpha == 0
|| mControllers.taskbarActivityContext.isPhoneMode()
|| (!mControllers.uiController.isHotseatIconOnTopWhenAligned()
&& mIconAlignment.value > 0);
@@ -780,9 +825,10 @@
* Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets
* should not be visible at the same time.
*/
- mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0);
+ float targetAlpha = hotseatVisible ? 1 : 0;
+ mLauncher.getHotseat().setIconsAlpha(targetAlpha, alphaChannel);
if (mIsQsbInline) {
- mLauncher.getHotseat().setQsbAlpha(hotseatVisible ? 1 : 0);
+ mLauncher.getHotseat().setQsbAlpha(targetAlpha, alphaChannel);
}
}
@@ -870,7 +916,7 @@
pw.println(String.format(
"%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value));
pw.println(String.format(
- "%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue()));
+ "%s\tmTaskbarAlphaForHome=%.2f", prefix, mTaskbarAlphaForHome.getValue()));
pw.println(String.format("%s\tmPrevState=%s", prefix,
mPrevState == null ? null : getStateString(mPrevState)));
pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState)));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 2370dfd..751a42a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -115,7 +115,8 @@
return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible()
&& !isShadeVisible
&& !mControllers.taskbarStashController.isStashed()
- && (mTaskbarVisible || showScrimForBubbles);
+ && (mTaskbarVisible || showScrimForBubbles)
+ && !mControllers.taskbarStashController.isHiddenForBubbles();
}
private float getScrimAlpha() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c1ed39a..7624afb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -82,6 +82,11 @@
private static final String TAG = "TaskbarStashController";
private static final boolean DEBUG = false;
+ /**
+ * Def. value for @param shouldBubblesFollow in
+ * {@link #updateAndAnimateTransientTaskbar(boolean)} */
+ public static boolean SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE = true;
+
public static final int FLAG_IN_APP = 1 << 0;
public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 1; // shade open, ...
public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 2; // setup wizard and AllSetActivity
@@ -94,6 +99,9 @@
public static final int FLAG_STASHED_SYSUI = 1 << 9; // app pinning,...
public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 10; // device is locked: keyguard, ...
public static final int FLAG_IN_OVERVIEW = 1 << 11; // launcher is in overview
+ // An internal no-op flag to determine whether we should delay the taskbar background animation
+ private static final int FLAG_DELAY_TASKBAR_BG_TAG = 1 << 12;
+ public static final int FLAG_STASHED_FOR_BUBBLES = 1 << 13; // show handle for stashed hotseat
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -115,7 +123,8 @@
// If any of these flags are enabled, the taskbar must be stashed.
private static final int FLAGS_FORCE_STASHED = FLAG_STASHED_SYSUI | FLAG_STASHED_DEVICE_LOCKED
- | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN;
+ | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN
+ | FLAG_STASHED_FOR_BUBBLES;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -388,6 +397,16 @@
return mIsStashed;
}
+ /** Sets the hotseat stashed. */
+ public void stashHotseat(boolean stash) {
+ mControllers.uiController.stashHotseat(stash);
+ }
+
+ /** Instantly un-stashes the hotseat. */
+ public void unStashHotseatInstantly() {
+ mControllers.uiController.unStashHotseatInstantly();
+ }
+
/**
* Returns whether the taskbar should be stashed in apps (e.g. user long pressed to stash).
*/
@@ -427,6 +446,11 @@
return hasAnyFlag(FLAG_IN_OVERVIEW);
}
+ /** Returns whether taskbar is hidden for bubbles. */
+ public boolean isHiddenForBubbles() {
+ return hasAnyFlag(FLAG_STASHED_FOR_BUBBLES);
+ }
+
/**
* Returns the height that taskbar will be touchable.
*/
@@ -489,9 +513,17 @@
/**
* Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
* If bubble bar exists, it will match taskbars stashing behavior.
+ * Will not delay taskbar background by default.
*/
public void updateAndAnimateTransientTaskbar(boolean stash) {
- updateAndAnimateTransientTaskbar(stash, /* shouldBubblesFollow= */ true);
+ updateAndAnimateTransientTaskbar(stash, SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE, false);
+ }
+
+ /**
+ * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
+ */
+ public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) {
+ updateAndAnimateTransientTaskbar(stash, shouldBubblesFollow, false);
}
/**
@@ -499,28 +531,47 @@
*
* @param stash whether transient taskbar should be stashed.
* @param shouldBubblesFollow whether bubbles should match taskbars behavior.
+ * @param delayTaskbarBackground whether we will delay the taskbar background animation
*/
- public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) {
+ public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow,
+ boolean delayTaskbarBackground) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
- if (
- stash
- && !mControllers.taskbarAutohideSuspendController
- .isSuspendedForTransientTaskbarInLauncher()
- && mControllers.taskbarAutohideSuspendController
- .isTransientTaskbarStashingSuspended()) {
+ if (stash
+ && !mControllers.taskbarAutohideSuspendController
+ .isSuspendedForTransientTaskbarInLauncher()
+ && mControllers.taskbarAutohideSuspendController
+ .isTransientTaskbarStashingSuspended()) {
// Avoid stashing if autohide is currently suspended.
return;
}
+ boolean shouldApplyState = false;
+
+ if (delayTaskbarBackground) {
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_DELAY_TASKBAR_BG_TAG, true);
+ shouldApplyState = true;
+ }
+
if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO) != stash) {
mTaskbarSharedState.taskbarWasStashedAuto = stash;
updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash);
+ shouldApplyState = true;
+ }
+
+ if (shouldApplyState) {
applyState();
}
+ // Effectively a no-opp to remove the tag.
+ if (delayTaskbarBackground) {
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_DELAY_TASKBAR_BG_TAG,
+ false);
+ mControllers.taskbarStashController.applyState(0);
+ }
+
mControllers.bubbleControllers.ifPresent(controllers -> {
if (shouldBubblesFollow) {
final boolean willStash = mIsStashedPredicate.test(mState);
@@ -584,14 +635,14 @@
/**
* Create a stash animation and save to {@link #mAnimator}.
*
- * @param isStashed whether it's a stash animation or an unstash animation
- * @param duration duration of the animation
- * @param animationType what transition type to play.
- * @param skipTaskbarBackgroundDelay Iff true, skips delaying the taskbar background.
- * @param jankTag tag to be used in jank monitor trace.
+ * @param isStashed whether it's a stash animation or an unstash animation
+ * @param duration duration of the animation
+ * @param animationType what transition type to play.
+ * @param shouldDelayBackground whether we should delay the taskbar bg animation
+ * @param jankTag tag to be used in jank monitor trace.
*/
private void createAnimToIsStashed(boolean isStashed, long duration,
- @StashAnimation int animationType, boolean skipTaskbarBackgroundDelay, String jankTag) {
+ @StashAnimation int animationType, boolean shouldDelayBackground, String jankTag) {
if (animationType == TRANSITION_UNSTASH_SUW_MANUAL && isStashed) {
// The STASH_ANIMATION_SUW_MANUAL must only be used during an unstash animation.
Log.e(TAG, "Illegal arguments:Using TRANSITION_UNSTASH_SUW_MANUAL to stash taskbar");
@@ -630,7 +681,7 @@
if (isTransientTaskbar) {
createTransientAnimToIsStashed(mAnimator, isStashed, duration,
- skipTaskbarBackgroundDelay, animationType);
+ shouldDelayBackground, animationType);
} else {
createAnimToIsStashed(mAnimator, isStashed, duration, stashTranslation, animationType);
}
@@ -736,7 +787,7 @@
}
private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- boolean skipTaskbarBackgroundDelay, @StashAnimation int animationType) {
+ boolean shouldDelayBackground, @StashAnimation int animationType) {
// Target values of the properties this is going to set
final float backgroundOffsetTarget = isStashed ? 1 : 0;
final float iconAlphaTarget = isStashed ? 0 : 1;
@@ -787,7 +838,10 @@
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
- if (enableScalingRevealHomeAnimation() && isStashed && !skipTaskbarBackgroundDelay) {
+
+ if (enableScalingRevealHomeAnimation()
+ && !isStashed
+ && shouldDelayBackground) {
play(as, getTaskbarBackgroundAnimatorWhenNotGoingHome(duration),
0, 0, LINEAR);
as.addListener(AnimatorListeners.forEndCallback(
@@ -958,13 +1012,29 @@
}
public void applyState() {
- applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION);
+ applyState(/* postApplyAction = */ null);
+ }
+
+ /** Applies state and performs action after state is applied. */
+ public void applyState(@Nullable Runnable postApplyAction) {
+ applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION, postApplyAction);
}
public void applyState(long duration) {
+ applyState(duration, /* postApplyAction = */ null);
+ }
+
+ private void applyState(long duration, @Nullable Runnable postApplyAction) {
Animator animator = createApplyStateAnimator(duration);
if (animator != null) {
+ if (postApplyAction != null) {
+ // performs action on animation end
+ animator.addListener(AnimatorListeners.forEndCallback(postApplyAction));
+ }
animator.start();
+ } else if (postApplyAction != null) {
+ // animator was not created, just execute the action
+ postApplyAction.run();
}
}
@@ -982,6 +1052,9 @@
*/
@Nullable
public Animator createApplyStateAnimator(long duration) {
+ if (mActivity.isPhoneMode()) {
+ return null;
+ }
return mStatePropertyHolder.createSetStateAnimator(mState, duration);
}
@@ -1027,10 +1100,6 @@
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) {
- if (mActivity.isPhoneMode()) {
- return;
- }
-
long animDuration = TASKBAR_STASH_DURATION;
long startDelay = 0;
@@ -1349,10 +1418,9 @@
mIsStashed = isStashed;
mLastStartedTransitionType = animationType;
- boolean skipTaskbarBgDelay = !hasAnyFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS)
- && hasAnyFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, changedFlags);
+ boolean shouldDelayBackground = hasAnyFlag(FLAG_DELAY_TASKBAR_BG_TAG);
// This sets mAnimator.
- createAnimToIsStashed(mIsStashed, duration, animationType, skipTaskbarBgDelay,
+ createAnimToIsStashed(mIsStashed, duration, animationType, shouldDelayBackground,
computeTaskbarJankMonitorTag(changedFlags));
return mAnimator;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
index 5b6fbef..17516f3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java
@@ -25,7 +25,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
/**
* Utility class that contains the different taskbar thresholds logic.
@@ -39,10 +38,6 @@
private static int getThreshold(Resources r, DeviceProfile dp, int thresholdDimen,
int multiplierDimen) {
- if (!FeatureFlags.ENABLE_DYNAMIC_TASKBAR_THRESHOLDS.get()) {
- return r.getDimensionPixelSize(thresholdDimen);
- }
-
float landscapeScreenHeight = dp.isLandscape ? dp.heightPx : dp.widthPx;
float screenPart = (landscapeScreenHeight * SCREEN_UNITS);
float defaultDp = dpiFromPx(screenPart, DisplayMetrics.DENSITY_DEVICE_STABLE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 6b1173a..9c8c2a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -428,4 +428,18 @@
public void setSkipLauncherVisibilityChange(boolean skip) {
mSkipLauncherVisibilityChange = skip;
}
+
+ /** Sets whether the hotseat is stashed */
+ public void stashHotseat(boolean stash) {
+ }
+
+ /** Un-stash the hotseat instantly */
+ public void unStashHotseatInstantly() {
+ }
+
+ /**
+ * Called when we want to unstash taskbar when user performs swipes up gesture.
+ */
+ public void onSwipeToUnstashTaskbar() {
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 32d6561..0389a11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -87,6 +87,7 @@
private final boolean mIsRtl;
private final TaskbarActivityContext mActivityContext;
+ @Nullable private BubbleBarLocation mBubbleBarLocation = null;
// Initialized in init.
private TaskbarViewCallbacks mControllerCallbacks;
@@ -197,7 +198,7 @@
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
- mShouldTryStartAlign = mActivityContext.isThreeButtonNav() && dp.startAlignTaskbar;
+ mShouldTryStartAlign = mActivityContext.shouldStartAlignTaskbar();
}
@Override
@@ -494,39 +495,60 @@
icon.setOnHoverListener(mControllerCallbacks.getIconOnHoverListener(icon));
}
+ /** Updates taskbar icons accordingly to the new bubble bar location. */
+ public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
+ if (mBubbleBarLocation == location) return;
+ mBubbleBarLocation = location;
+ requestLayout();
+ }
+
+ /**
+ * Returns translation X for the taskbar icons for provided {@link BubbleBarLocation}. If the
+ * bubble bar is not enabled, or location of the bubble bar is the same, or taskbar is not start
+ * aligned - returns 0.
+ */
+ public float getTranslationXForBubbleBarPosition(BubbleBarLocation location) {
+ if (!mControllerCallbacks.isBubbleBarEnabledInPersistentTaskbar()
+ || location == mBubbleBarLocation
+ || !mActivityContext.shouldStartAlignTaskbar()
+ ) {
+ return 0;
+ }
+ Rect iconsBounds = getIconLayoutBounds();
+ return getTaskBarIconsEndForBubbleBarLocation(location) - iconsBounds.right;
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int count = getChildCount();
- DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int spaceNeeded = getIconLayoutWidth();
- int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
boolean layoutRtl = isLayoutRtl();
- int centerAlignIconEnd = right - (right - left - spaceNeeded) / 2;
- int iconEnd;
-
+ DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+ int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
+ int centerAlignIconEnd = (right + left + spaceNeeded) / 2;
+ int iconEnd = centerAlignIconEnd;
if (mShouldTryStartAlign) {
- // Taskbar is aligned to the start
int startSpacingPx = deviceProfile.inlineNavButtonsEndSpacingPx;
-
- if (layoutRtl) {
- iconEnd = right - startSpacingPx;
+ if (mControllerCallbacks.isBubbleBarEnabledInPersistentTaskbar()
+ && mBubbleBarLocation != null
+ && mActivityContext.shouldStartAlignTaskbar()) {
+ iconEnd = (int) getTaskBarIconsEndForBubbleBarLocation(mBubbleBarLocation);
} else {
- iconEnd = startSpacingPx + spaceNeeded;
+ if (layoutRtl) {
+ iconEnd = right - startSpacingPx;
+ } else {
+ iconEnd = startSpacingPx + spaceNeeded;
+ }
+ boolean needMoreSpaceForNav = layoutRtl
+ ? navSpaceNeeded > (iconEnd - spaceNeeded)
+ : iconEnd > (right - navSpaceNeeded);
+ if (needMoreSpaceForNav) {
+ // Add offset to account for nav bar when taskbar is centered
+ int offset = layoutRtl
+ ? navSpaceNeeded - (centerAlignIconEnd - spaceNeeded)
+ : (right - navSpaceNeeded) - centerAlignIconEnd;
+ iconEnd = centerAlignIconEnd + offset;
+ }
}
- } else {
- iconEnd = centerAlignIconEnd;
- }
-
- boolean needMoreSpaceForNav = layoutRtl
- ? navSpaceNeeded > (iconEnd - spaceNeeded)
- : iconEnd > (right - navSpaceNeeded);
- if (needMoreSpaceForNav) {
- // Add offset to account for nav bar when taskbar is centered
- int offset = layoutRtl
- ? navSpaceNeeded - (centerAlignIconEnd - spaceNeeded)
- : (right - navSpaceNeeded) - centerAlignIconEnd;
-
- iconEnd = centerAlignIconEnd + offset;
}
// Currently, we support only one device with display cutout and we only are concern about
@@ -558,6 +580,7 @@
mIconLayoutBounds.right = iconEnd;
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
+ int count = getChildCount();
for (int i = count; i > 0; i--) {
View child = getChildAt(i - 1);
if (child == mQsb) {
@@ -770,4 +793,19 @@
}
return mAllAppsButtonContainer;
}
+
+ /**
+ * This method only works for bubble bar enabled in persistent task bar and the taskbar is start
+ * aligned.
+ */
+ private float getTaskBarIconsEndForBubbleBarLocation(BubbleBarLocation location) {
+ DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
+ boolean navbarOnRight = location.isOnLeft(isLayoutRtl());
+ int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
+ if (navbarOnRight) {
+ return getWidth() - navSpaceNeeded;
+ } else {
+ return navSpaceNeeded + getIconLayoutWidth();
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 5ec00ac..5c8d439 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -28,6 +28,7 @@
import com.android.internal.jank.Cuj;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
/**
@@ -127,4 +128,10 @@
}
return null;
}
+
+ /** Returns true if bubble bar controllers present and enabled in persistent taskbar. */
+ public boolean isBubbleBarEnabledInPersistentTaskbar() {
+ return Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 292b9ed..b663ccb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -29,7 +29,10 @@
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
+import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_ALPHA_DURATION_MS;
+import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
+import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_NAV_BAR_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
@@ -66,6 +69,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.TaskItemInfo;
+import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
@@ -74,6 +78,8 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
+import com.android.wm.shell.Flags;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.Set;
@@ -82,7 +88,8 @@
/**
* Handles properties/data collection, then passes the results to TaskbarView to render.
*/
-public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController {
+public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController,
+ BubbleBarController.BubbleBarLocationListener {
private static final String TAG = "TaskbarViewController";
@@ -122,6 +129,14 @@
private final AnimatedFloat mTaskbarIconTranslationXForPinning = new AnimatedFloat(
this::updateTaskbarIconTranslationXForPinning);
+ private final AnimatedFloat mIconsTranslationXForNavbar = new AnimatedFloat(
+ this::updateTranslationXForNavBar);
+
+ @Nullable
+ private Animator mTaskbarShiftXAnim;
+ @Nullable
+ private BubbleBarLocation mCurrentBubbleBarLocation;
+
private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
this::updateTranslationY);
@@ -227,6 +242,54 @@
}
}
+ /** Adjusts start aligned taskbar layout accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
+ updateCurrentBubbleBarLocation(location);
+ if (!shouldMoveTaskbarOnBubbleBarLocationUpdate()) return;
+ cancelTaskbarShiftAnimation();
+ // reset translation x, taskbar will position icons with the updated location
+ mIconsTranslationXForNavbar.updateValue(0);
+ mTaskbarView.onBubbleBarLocationUpdated(location);
+ }
+
+ /** Animates start aligned taskbar accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationAnimated(BubbleBarLocation location) {
+ if (!updateCurrentBubbleBarLocation(location)
+ || !shouldMoveTaskbarOnBubbleBarLocationUpdate()) {
+ return;
+ }
+ cancelTaskbarShiftAnimation();
+ float translationX = mTaskbarView.getTranslationXForBubbleBarPosition(location);
+ mTaskbarShiftXAnim = createTaskbarIconsShiftAnimator(translationX);
+ mTaskbarShiftXAnim.start();
+ }
+
+ /** Updates the mCurrentBubbleBarLocation, returns {@code} true if location is updated. */
+ private boolean updateCurrentBubbleBarLocation(BubbleBarLocation location) {
+ if (mCurrentBubbleBarLocation == location || location == null) {
+ return false;
+ } else {
+ mCurrentBubbleBarLocation = location;
+ return true;
+ }
+ }
+
+ /** Returns whether taskbar should be moved on the bubble bar location update. */
+ private boolean shouldMoveTaskbarOnBubbleBarLocationUpdate() {
+ return Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent()
+ && mActivity.shouldStartAlignTaskbar()
+ && mActivity.isThreeButtonNav();
+ }
+
+ private void cancelTaskbarShiftAnimation() {
+ if (mTaskbarShiftXAnim != null) {
+ mTaskbarShiftXAnim.cancel();
+ }
+ }
+
/**
* Announcement for Accessibility when Taskbar stashes/unstashes.
*/
@@ -460,6 +523,17 @@
+ mTaskbarIconTranslationYForSpringOnStash);
}
+ private void updateTranslationXForNavBar() {
+ View[] iconViews = mTaskbarView.getIconViews();
+ float translationX = mIconsTranslationXForNavbar.value;
+ for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
+ View iconView = iconViews[iconIndex];
+ MultiTranslateDelegate translateDelegate =
+ ((Reorderable) iconView).getTranslateDelegate();
+ translateDelegate.getTranslationX(INDEX_NAV_BAR_ANIM).setValue(translationX);
+ }
+ }
+
/**
* Computes translation y for taskbar pinning.
*/
@@ -763,7 +837,7 @@
// plays iconAlignment to 1 really fast, therefore moving the fading towards the end
// to avoid icons disappearing rather than fading out visually.
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
- } else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())
+ } else if ((isAllAppsButton && !FeatureFlags.enableAllAppsButtonInHotseat())
|| (isTaskbarDividerView && enableTaskbarPinning())
|| (isRecentTask && !isRecentsInHotseat)) {
if (!isToHome
@@ -1018,4 +1092,12 @@
public static void enableModelLoadingForTests(boolean enable) {
sEnableModelLoadingForTests = enable;
}
+
+ private ObjectAnimator createTaskbarIconsShiftAnimator(float translationX) {
+ ObjectAnimator animator = mIconsTranslationXForNavbar.animateToValue(translationX);
+ animator.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS);
+ animator.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
+ animator.setInterpolator(Interpolators.EMPHASIZED);
+ return animator;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 5d91acd..a46845a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -17,13 +17,10 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.view.View;
import androidx.annotation.Nullable;
-import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import java.util.Optional;
@@ -47,23 +44,6 @@
}
@Override
- protected View inflateSearchBar() {
- if (isSearchSupported()) {
- return super.inflateSearchBar();
- }
-
- // Remove top padding of header, since we do not have any search
- mHeader.setPadding(mHeader.getPaddingLeft(), 0,
- mHeader.getPaddingRight(), mHeader.getPaddingBottom());
-
- TaskbarAllAppsFallbackSearchContainer searchView =
- new TaskbarAllAppsFallbackSearchContainer(getContext(), null);
- searchView.setId(R.id.search_container_all_apps);
- searchView.setVisibility(GONE);
- return searchView;
- }
-
- @Override
public void invalidateHeader() {
super.invalidateHeader();
Optional.ofNullable(mOnInvalidateHeaderListener).ifPresent(
@@ -71,11 +51,6 @@
}
@Override
- protected boolean isSearchSupported() {
- return FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get();
- }
-
- @Override
public boolean isInAllApps() {
// All apps is always open
return true;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java
deleted file mode 100644
index 53fe06d..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2022 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.allapps;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.ExtendedEditText;
-import com.android.launcher3.allapps.ActivityAllAppsContainerView;
-import com.android.launcher3.allapps.SearchUiManager;
-
-/** Empty search container for Taskbar All Apps used as a fallback if search is not supported. */
-public class TaskbarAllAppsFallbackSearchContainer extends View implements SearchUiManager {
- public TaskbarAllAppsFallbackSearchContainer(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public TaskbarAllAppsFallbackSearchContainer(
- Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- public void initializeSearch(ActivityAllAppsContainerView<?> containerView) {
- // Do nothing.
- }
-
- @Override
- public void resetSearch() {
- // Do nothing.
- }
-
- @Nullable
- @Override
- public ExtendedEditText getEditText() {
- return null;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index f5ac66f..5830095 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -39,7 +39,6 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsViewController.TaskbarAllAppsCallbacks;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.util.Themes;
@@ -180,9 +179,7 @@
mContent = mAppsView;
// Setup header protection for search bar, if enabled.
- if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- mAppsView.setOnInvalidateHeaderListener(this::invalidate);
- }
+ mAppsView.setOnInvalidateHeaderListener(this::invalidate);
DeviceProfile dp = mActivityContext.getDeviceProfile();
setShiftRange(dp.allAppsShiftRange);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 4d0b376..6b72ab6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -21,7 +21,6 @@
import com.android.launcher3.R
import com.android.launcher3.allapps.AllAppsTransitionListener
import com.android.launcher3.anim.PendingAnimation
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.dragndrop.DragOptions.PreDragCondition
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.util.ResourceBasedOverride
@@ -61,16 +60,11 @@
companion object {
@JvmStatic
- fun newInstance(context: Context): TaskbarSearchSessionController {
- if (!FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- return TaskbarSearchSessionController()
- }
-
- return Overrides.getObject(
+ fun newInstance(context: Context): TaskbarSearchSessionController =
+ Overrides.getObject(
TaskbarSearchSessionController::class.java,
context,
R.string.taskbar_search_session_controller_class,
)
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index d70a317..6860004 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -118,6 +118,7 @@
private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController;
private BubblePinController mBubblePinController;
private BubbleCreator mBubbleCreator;
+ private BubbleBarLocationListener mBubbleBarLocationListener;
// Cache last sent top coordinate to avoid sending duplicate updates to shell
private int mLastSentBubbleBarTop;
@@ -176,6 +177,7 @@
/** Initializes controllers. */
public void init(BubbleControllers bubbleControllers,
+ BubbleBarLocationListener bubbleBarLocationListener,
ImeVisibilityChecker imeVisibilityChecker) {
mImeVisibilityChecker = imeVisibilityChecker;
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
@@ -183,6 +185,7 @@
mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
mBubblePinController = bubbleControllers.bubblePinController;
mBubbleCreator = bubbleControllers.bubbleCreator;
+ mBubbleBarLocationListener = bubbleBarLocationListener;
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(
@@ -488,12 +491,16 @@
private void updateBubbleBarLocationInternal(BubbleBarLocation location) {
mBubbleBarViewController.setBubbleBarLocation(location);
mBubbleStashController.setBubbleBarLocation(location);
+ mBubbleBarLocationListener.onBubbleBarLocationUpdated(location);
}
@Override
public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
MAIN_EXECUTOR.execute(
- () -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
+ () -> {
+ mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation);
+ mBubbleBarLocationListener.onBubbleBarLocationAnimated(bubbleBarLocation);
+ });
}
/** Notifies WMShell to show the expanded view. */
@@ -518,4 +525,14 @@
/** Whether the IME is visible. */
boolean isImeVisible();
}
+
+ /** Listener of {@link BubbleBarLocation} updates. */
+ public interface BubbleBarLocationListener {
+
+ /** Called when {@link BubbleBarLocation} is animated, but change is not yet final. */
+ void onBubbleBarLocationAnimated(BubbleBarLocation location);
+
+ /** Called when {@link BubbleBarLocation} is updated permanently. */
+ void onBubbleBarLocationUpdated(BubbleBarLocation location);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt
new file mode 100644
index 0000000..8e176ac
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt
@@ -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.taskbar.bubbles
+
+import com.android.launcher3.taskbar.bubbles.BubbleBarController.BubbleBarLocationListener
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+
+/** Composite implementation of [BubbleBarLocationListener] interface */
+class BubbleBarLocationCompositeListener(private val listeners: List<BubbleBarLocationListener>) :
+ BubbleBarLocationListener {
+
+ constructor(vararg listeners: BubbleBarLocationListener) : this(listOf(*listeners))
+
+ override fun onBubbleBarLocationAnimated(location: BubbleBarLocation?) {
+ listeners.forEach { it.onBubbleBarLocationAnimated(location) }
+ }
+
+ override fun onBubbleBarLocationUpdated(location: BubbleBarLocation?) {
+ listeners.forEach { it.onBubbleBarLocationUpdated(location) }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
index 9c34307..a34fab2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -27,6 +27,7 @@
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.BubbleBarController.BubbleBarLocationListener
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.bubbles.BaseBubblePinController
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
@@ -42,12 +43,17 @@
private lateinit var bubbleBarViewController: BubbleBarViewController
private lateinit var bubbleStashController: BubbleStashController
+ private lateinit var bubbleBarLocationListener: BubbleBarLocationListener
private var exclRectWidth: Float = 0f
private var exclRectHeight: Float = 0f
private var dropTargetView: View? = null
- fun init(bubbleControllers: BubbleControllers) {
+ fun init(
+ bubbleControllers: BubbleControllers,
+ bubbleBarLocationListener: BubbleBarLocationListener
+ ) {
+ this.bubbleBarLocationListener = bubbleBarLocationListener
bubbleBarViewController = bubbleControllers.bubbleBarViewController
bubbleStashController = bubbleControllers.bubbleStashController
exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width)
@@ -86,6 +92,7 @@
val bounds = bubbleBarViewController.bubbleBarBounds
val horizontalMargin = bubbleBarViewController.horizontalMargin
+ bubbleBarLocationListener.onBubbleBarLocationAnimated(location)
dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> {
width = bounds.width()
height = bounds.height()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 14f6e3a..d454fd7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -95,11 +95,11 @@
private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L;
private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L;
- private static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L;
+ public static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L;
// During fade out animation we shift the bubble bar 1/80th of the screen width
private static final float FADE_OUT_ANIM_POSITION_SHIFT = 1 / 80f;
- private static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L;
+ public static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L;
// Use STIFFNESS_MEDIUMLOW which is not defined in the API constants
private static final float FADE_IN_ANIM_POSITION_SPRING_STIFFNESS = 400f;
// During fade in animation we shift the bubble bar 1/60th of the screen width
@@ -187,6 +187,9 @@
private BubbleView mDismissedByDragBubbleView;
private float mAlphaDuringDrag = 1f;
+ /** Additional translation in the y direction that is applied to each bubble */
+ private float mBubbleOffsetY;
+
private Controller mController;
private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
@@ -335,6 +338,16 @@
}
/**
+ * Sets offset of each bubble view in the y direction from the base position in the bar.
+ */
+ public void setBubbleOffsetY(float offsetY) {
+ mBubbleOffsetY = offsetY;
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setTranslationY(getBubbleTranslationY());
+ }
+ }
+
+ /**
* Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
*
* @param newIconSize new icon size
@@ -676,7 +689,7 @@
}
setAlphaDuringBubbleDrag(1f);
setTranslationX(0f);
- if (getBubbleChildCount() > 0) {
+ if (mIsBarExpanded && getBubbleChildCount() > 0) {
setAlpha(1f);
}
}
@@ -997,10 +1010,7 @@
final float expandedWidth = expandedWidth();
final float collapsedWidth = collapsedWidth();
int childCount = getChildCount();
- float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
- float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
- // When translating X & Y the scale is ignored, so need to deduct it from the translations
- final float ty = bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
+ final float ty = getBubbleTranslationY();
final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
// elevation state is opposite to widthState - when expanded all icons are flat
float elevationState = (1 - widthState);
@@ -1125,15 +1135,25 @@
translationX = 0f;
}
} else {
- if (bubbleIndex == 1 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) {
- translationX = mIconOverlapAmount;
- } else {
+ // when the bar is on the right, the first bubble always has translation 0. the only
+ // case where another bubble has translation 0 is when we only have 1 bubble and the
+ // overflow. otherwise all other bubbles should be shifted by the overlap amount.
+ if (bubbleIndex == 0 || getBubbleChildCount() == 1) {
translationX = 0f;
+ } else {
+ translationX = mIconOverlapAmount;
}
}
return mBubbleBarPadding + translationX - getScaleIconShift();
}
+ private float getBubbleTranslationY() {
+ float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
+ float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
+ // When translating X & Y the scale is ignored, so need to deduct it from the translations
+ return mBubbleOffsetY + bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
+ }
+
/**
* Reorders the views to match the provided list.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 570b1b9..025c038 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,11 +18,8 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static com.android.launcher3.taskbar.bubbles.BubbleView.STASH_TRANSLATION_Y;
-
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -97,6 +94,8 @@
this::updateBackgroundScaleY);
private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
this::updateTranslationY);
+ private final AnimatedFloat mBubbleOffsetY = new AnimatedFloat(
+ this::updateBubbleOffsetY);
// Modified when swipe up is happening on the bubble bar or task bar.
private float mBubbleBarSwipeUpTranslationY;
@@ -299,6 +298,10 @@
return mBubbleBarTranslationY;
}
+ public AnimatedFloat getBubbleOffsetY() {
+ return mBubbleOffsetY;
+ }
+
public float getBubbleBarCollapsedWidth() {
return mBarView.collapsedWidth();
}
@@ -437,7 +440,7 @@
if (hidden) {
mBarView.setAlpha(0);
mBarView.setExpanded(false);
- updatePersistentTaskbar(/* isBubbleBarExpanded = */ false);
+ adjustTaskbarAndHotseatToBubbleBarState(/* isBubbleBarExpanded = */ false);
}
mActivity.bubbleBarVisibilityChanged(!hidden);
}
@@ -576,6 +579,10 @@
mBarView.setBubbleAlpha(alpha);
}
+ private void updateBubbleOffsetY(float transY) {
+ mBarView.setBubbleOffsetY(transY);
+ }
+
private void updateBackgroundAlpha(float alpha) {
mBarView.setBackgroundAlpha(alpha);
}
@@ -728,7 +735,7 @@
public void setExpanded(boolean isExpanded) {
if (isExpanded != mBarView.isExpanded()) {
mBarView.setExpanded(isExpanded);
- updatePersistentTaskbar(isExpanded);
+ adjustTaskbarAndHotseatToBubbleBarState(isExpanded);
if (!isExpanded) {
mSystemUiProxy.collapseBubbles();
} else {
@@ -739,13 +746,25 @@
}
}
- private void updatePersistentTaskbar(boolean isBubbleBarExpanded) {
- if (mBubbleStashController.isTransientTaskBar()) return;
- boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
- mTaskbarViewPropertiesProvider
- .getIconsAlpha()
- .animateToValue(hideTaskbar ? 0 : 1)
- .start();
+ /**
+ * Hides the persistent taskbar if it is going to intersect with the expanded bubble bar if in
+ * app or overview. Set the hotseat stashed state if on launcher home screen. If not on launcher
+ * home screen and hotseat is stashed immediately un-stashes the hotseat.
+ */
+ private void adjustTaskbarAndHotseatToBubbleBarState(boolean isBubbleBarExpanded) {
+ if (mBubbleStashController.isBubblesShowingOnHome()) {
+ mTaskbarStashController.stashHotseat(isBubbleBarExpanded);
+ } else if (!mBubbleStashController.isTransientTaskBar()) {
+ boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
+ mTaskbarViewPropertiesProvider
+ .getIconsAlpha()
+ .animateToValue(hideTaskbar ? 0 : 1)
+ .start();
+ }
+ if (!mBubbleStashController.isBubblesShowingOnHome()
+ && mTaskbarStashController.isHiddenForBubbles()) {
+ mTaskbarStashController.unStashHotseatInstantly();
+ }
}
/** Return {@code true} if expanded bubble bar would intersect the taskbar. */
@@ -864,6 +883,11 @@
mBoundsChangeListener = listener;
}
+ /** Called when the controller is destroyed. */
+ public void onDestroy() {
+ adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false);
+ }
+
/**
* Create an animator for showing or hiding bubbles when stashed state changes
*
@@ -874,14 +898,9 @@
mBubbleStashController.getHandleBounds(stashedHandleBounds);
int childCount = mBarView.getChildCount();
float newChildWidth = (float) stashedHandleBounds.width() / childCount;
- float stashTranslationY = -mBubbleStashController.getBubbleBarTranslationY();
AnimatorSet animatorSet = new AnimatorSet();
for (int i = 0; i < childCount; i++) {
BubbleView child = (BubbleView) mBarView.getChildAt(i);
- final float startTransY = isStashed ? 0f : stashTranslationY;
- final float endTransY = isStashed ? stashTranslationY : 0f;
- animatorSet.play(
- ObjectAnimator.ofFloat(child, STASH_TRANSLATION_Y, startTransY, endTransY));
animatorSet.play(
createRevealAnimForBubble(child, isStashed, stashedHandleBounds,
newChildWidth));
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index e00916a..a66df4c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -76,7 +76,14 @@
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarControllers taskbarControllers) {
+ // TODO(b/346381754) add TaskbarLauncherStateController implementation to adjust the hotseat
+ BubbleBarLocationCompositeListener bubbleBarLocationListeners =
+ new BubbleBarLocationCompositeListener(
+ taskbarControllers.navbarButtonsViewController,
+ taskbarControllers.taskbarViewController
+ );
bubbleBarController.init(this,
+ bubbleBarLocationListeners,
taskbarControllers.navbarButtonsViewController::isImeVisible);
bubbleStashedHandleViewController.ifPresent(
controller -> controller.init(/* bubbleControllers = */ this));
@@ -102,7 +109,7 @@
});
bubbleDragController.init(/* bubbleControllers = */ this);
bubbleDismissController.init(/* bubbleControllers = */ this);
- bubbleBarPinController.init(this);
+ bubbleBarPinController.init(this, bubbleBarLocationListeners);
bubblePinController.init(this);
mPostInitRunnables.executeAllAndDestroy();
@@ -124,6 +131,7 @@
public void onDestroy() {
bubbleStashedHandleViewController.ifPresent(BubbleStashedHandleViewController::onDestroy);
bubbleBarController.onDestroy();
+ bubbleBarViewController.onDestroy();
}
/** Dumps bubble controllers state. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index cc6b49a..561df5c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -27,7 +27,6 @@
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -50,27 +49,12 @@
public static final int DEFAULT_PATH_SIZE = 100;
- public static FloatProperty<BubbleView> STASH_TRANSLATION_Y = new FloatProperty<>(
- "stashTranslationY") {
- @Override
- public void setValue(BubbleView bubbleView, float transY) {
- bubbleView.setStashTranslationY(transY);
- }
-
- @Override
- public Float get(BubbleView bubbleView) {
- return bubbleView.mStashTranslationY;
- }
- };
-
private final ImageView mBubbleIcon;
private final ImageView mAppIcon;
private int mBubbleSize;
private float mDragTranslationX;
private float mOffsetX;
- private float mTranslationY;
- private float mStashTranslationY;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
@@ -177,24 +161,6 @@
setTranslationX(mDragTranslationX + mOffsetX);
}
- /**
- * Set translation in y direction during stash and unstash from handle
- */
- public void setStashTranslationY(float translationY) {
- mStashTranslationY = translationY;
- applyTranslationY();
- }
-
- @Override
- public void setTranslationY(float translationY) {
- mTranslationY = translationY;
- applyTranslationY();
- }
-
- private void applyTranslationY() {
- super.setTranslationY(mTranslationY + mStashTranslationY);
- }
-
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
new file mode 100644
index 0000000..152dcf7
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.bubbles.flyout
+
+import android.view.Gravity
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.android.launcher3.R
+
+/** Creates and manages the visibility of the [BubbleBarFlyoutView]. */
+class BubbleBarFlyoutController(
+ private val container: FrameLayout,
+ private val positioner: BubbleBarFlyoutPositioner,
+) {
+
+ private var flyout: BubbleBarFlyoutView? = null
+ val horizontalMargin =
+ container.context.resources.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
+
+ fun setUpFlyout(message: BubbleBarFlyoutMessage) {
+ flyout?.let(container::removeView)
+ val flyout = BubbleBarFlyoutView(container.context)
+
+ flyout.translationY = positioner.targetTy
+
+ val lp =
+ FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ Gravity.BOTTOM or if (positioner.isOnLeft) Gravity.LEFT else Gravity.RIGHT,
+ )
+ lp.marginStart = horizontalMargin
+ lp.marginEnd = horizontalMargin
+ container.addView(flyout, lp)
+
+ flyout.setData(message)
+ this.flyout = flyout
+ }
+
+ fun hideFlyout() {
+ val flyout = this.flyout ?: return
+ container.removeView(flyout)
+ this.flyout = null
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt
new file mode 100644
index 0000000..7298297
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.bubbles.flyout
+
+import android.graphics.drawable.Drawable
+
+data class BubbleBarFlyoutMessage(
+ val senderAvatar: Drawable?,
+ val senderName: CharSequence,
+ val message: CharSequence,
+ val isGroupChat: Boolean,
+)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt
new file mode 100644
index 0000000..deed1f5
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.bubbles.flyout
+
+/** Provides positioning data to the flyout view. */
+interface BubbleBarFlyoutPositioner {
+
+ /** Whether the flyout view should be positioned on left or the right edge. */
+ val isOnLeft: Boolean
+
+ /** The target translation Y that the flyout view should have when displayed. */
+ val targetTy: Float
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
new file mode 100644
index 0000000..d3dc3f8
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.bubbles.flyout
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.view.LayoutInflater
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.launcher3.R
+
+/** The flyout view used to notify the user of a new bubble notification. */
+class BubbleBarFlyoutView(context: Context) : ConstraintLayout(context) {
+
+ private val sender: TextView by
+ lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_name) }
+
+ private val avatar: ImageView by
+ lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_avatar) }
+
+ private val message: TextView by
+ lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
+
+ private val flyoutHorizontalPadding by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
+ }
+
+ private val maxFlyoutWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_max_width)
+ }
+
+ private val cornerRadius: Float
+ private var backgroundColor = Color.BLACK
+
+ /**
+ * The paint used to draw the background, whose color changes as the flyout transitions to the
+ * tinted notification dot.
+ */
+ private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true)
+
+ val ta = context.obtainStyledAttributes(intArrayOf(android.R.attr.dialogCornerRadius))
+ cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat()
+ ta.recycle()
+
+ setWillNotDraw(false)
+ clipChildren = false
+ clipToPadding = false
+
+ val horizontalPadding =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
+ val verticalPadding =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_vertical)
+ setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding)
+ translationZ =
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat()
+ applyConfigurationColors(resources.configuration)
+ }
+
+ fun setData(flyoutMessage: BubbleBarFlyoutMessage) {
+ // the avatar is only displayed in group chat messages
+ if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) {
+ avatar.visibility = VISIBLE
+ avatar.setImageDrawable(flyoutMessage.senderAvatar)
+ } else {
+ avatar.visibility = GONE
+ }
+
+ val maxTextViewWidth = maxFlyoutWidth - flyoutHorizontalPadding * 2
+ if (flyoutMessage.senderName.isEmpty()) {
+ sender.visibility = GONE
+ } else {
+ sender.maxWidth = maxTextViewWidth
+ sender.text = flyoutMessage.senderName
+ sender.visibility = VISIBLE
+ }
+
+ message.maxWidth = maxTextViewWidth
+ message.text = flyoutMessage.message
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ canvas.drawRoundRect(
+ 0f,
+ 0f,
+ width.toFloat(),
+ height.toFloat(),
+ cornerRadius,
+ cornerRadius,
+ backgroundPaint,
+ )
+ super.onDraw(canvas)
+ }
+
+ private fun applyConfigurationColors(configuration: Configuration) {
+ val nightModeFlags = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ val isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES
+ val defaultBackgroundColor = if (isNightModeOn) Color.BLACK else Color.WHITE
+ val defaultTextColor = if (isNightModeOn) Color.WHITE else Color.BLACK
+ val ta =
+ context.obtainStyledAttributes(
+ intArrayOf(
+ com.android.internal.R.attr.materialColorSurfaceContainer,
+ com.android.internal.R.attr.materialColorOnSurface,
+ com.android.internal.R.attr.materialColorOnSurfaceVariant,
+ )
+ )
+ backgroundColor = ta.getColor(0, defaultBackgroundColor)
+ sender.setTextColor(ta.getColor(1, defaultTextColor))
+ message.setTextColor(ta.getColor(2, defaultTextColor))
+ ta.recycle()
+ backgroundPaint.color = backgroundColor
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 5d1e890..4f0337d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -47,7 +47,7 @@
class TransientBubbleStashController(
private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
- private val context: Context
+ private val context: Context,
) : BubbleStashController {
private lateinit var bubbleBarViewController: BubbleBarViewController
@@ -70,6 +70,7 @@
private lateinit var bubbleBarBubbleAlpha: AnimatedFloat
private lateinit var bubbleBarBackgroundAlpha: AnimatedFloat
private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
+ private lateinit var bubbleBarBubbleTranslationY: AnimatedFloat
private lateinit var bubbleBarBackgroundScaleX: AnimatedFloat
private lateinit var bubbleBarBackgroundScaleY: AnimatedFloat
private val handleCenterFromScreenBottom =
@@ -143,13 +144,14 @@
taskbarInsetsController: TaskbarInsetsController,
bubbleBarViewController: BubbleBarViewController,
bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
- controllersAfterInitAction: ControllersAfterInitAction
+ controllersAfterInitAction: ControllersAfterInitAction,
) {
this.taskbarInsetsController = taskbarInsetsController
this.bubbleBarViewController = bubbleBarViewController
this.bubbleStashedHandleViewController = bubbleStashedHandleViewController
this.controllersAfterInitAction = controllersAfterInitAction
bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
+ bubbleBarBubbleTranslationY = bubbleBarViewController.bubbleOffsetY
// bubble bar has only alpha property, getting it at index 0
bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0)
bubbleBarBubbleAlpha = bubbleBarViewController.bubbleBarBubbleAlpha
@@ -170,7 +172,7 @@
bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
bubbleBarAlpha.animateToValue(1f),
bubbleBarBubbleAlpha.animateToValue(1f),
- bubbleBarBackgroundAlpha.animateToValue(1f)
+ bubbleBarBackgroundAlpha.animateToValue(1f),
)
} else {
isStashed = true
@@ -301,23 +303,24 @@
private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet {
val animatorSet = AnimatorSet()
- val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
- val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
animatorSet.play(
createBackgroundAlphaAnimator(isStashed).apply {
+ val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+ val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
this.duration = max(0L, alphaDuration - alphaDelay)
this.startDelay = alphaDelay
this.interpolator = LINEAR
}
)
- val iconAlphaTarget = if (isStashed) 0f else 1f
animatorSet.play(
- bubbleBarBubbleAlpha.animateToValue(iconAlphaTarget).apply {
- this.duration = TASKBAR_STASH_ALPHA_DURATION
- this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
- this.interpolator = LINEAR
- }
+ bubbleBarBubbleAlpha
+ .animateToValue(getBarAlphaStart(isStashed), getBarAlphaEnd(isStashed))
+ .apply {
+ this.duration = TASKBAR_STASH_ALPHA_DURATION
+ this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
+ this.interpolator = LINEAR
+ }
)
animatorSet.play(
@@ -334,6 +337,16 @@
}
)
+ // Animate bubble translation to keep reveal animation in the bounds of the bar
+ val bubbleTyStart = if (isStashed) 0f else -bubbleBarTranslationY
+ val bubbleTyEnd = if (isStashed) -bubbleBarTranslationY else 0f
+ animatorSet.play(
+ bubbleBarBubbleTranslationY.animateToValue(bubbleTyStart, bubbleTyEnd).apply {
+ this.duration = duration
+ this.interpolator = EMPHASIZED
+ }
+ )
+
animatorSet.play(
bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply {
this.duration = duration
@@ -359,11 +372,15 @@
)
animatorSet.doOnStart {
- if (!isStashed) {
- bubbleBarBackgroundAlpha.updateValue(0f)
- bubbleBarBubbleAlpha.updateValue(0f)
- bubbleBarAlpha.value = 1f
- }
+ // Update the start value for bubble view and background alpha when the entire animation
+ // begins.
+ // Alpha animation has a delay, and if we set the initial values at the start of the
+ // alpha animation, it will cause flickers.
+ bubbleBarBubbleAlpha.updateValue(getBarAlphaStart(isStashed))
+ bubbleBarBackgroundAlpha.updateValue(getBarAlphaStart(isStashed))
+ // We animate alpha for background and bubble views separately. Make sure the container
+ // is always visible.
+ bubbleBarAlpha.value = 1f
}
animatorSet.doOnEnd {
animator = null
@@ -373,6 +390,9 @@
// reset bubble view alpha
bubbleBarBubbleAlpha.updateValue(1f)
bubbleBarBackgroundAlpha.updateValue(1f)
+ // reset stash translation
+ translationYDuringStash.updateValue(0f)
+ bubbleBarBubbleTranslationY.updateValue(0f)
bubbleBarViewController.isExpanded = false
}
taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -382,14 +402,29 @@
}
private fun createBackgroundAlphaAnimator(isStashed: Boolean): AnimatorSet {
- val stashHandleAlphaTarget = if (isStashed) 1f else 0f
- val barAlphaTarget = if (isStashed) 0f else 1f
return AnimatorSet().apply {
- play(bubbleBarBackgroundAlpha.animateToValue(barAlphaTarget))
- play(stashHandleViewAlpha?.animateToValue(stashHandleAlphaTarget))
+ play(
+ bubbleBarBackgroundAlpha.animateToValue(
+ getBarAlphaStart(isStashed),
+ getBarAlphaEnd(isStashed),
+ )
+ )
+ play(stashHandleViewAlpha?.animateToValue(getHandleAlphaEnd(isStashed)))
}
}
+ private fun getBarAlphaStart(isStashed: Boolean): Float {
+ return if (isStashed) 1f else 0f
+ }
+
+ private fun getBarAlphaEnd(isStashed: Boolean): Float {
+ return if (isStashed) 0f else 1f
+ }
+
+ private fun getHandleAlphaEnd(isStashed: Boolean): Float {
+ return if (isStashed) 1f else 0f
+ }
+
private fun createSpringOnStashAnimator(isStashed: Boolean): Animator {
if (!isStashed) {
// Animate the stash translation back to 0
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index 726800c..e6c0b2f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -30,7 +30,6 @@
import androidx.core.view.setPadding
import com.android.launcher3.R
import com.android.launcher3.Utilities.dpToPx
-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
@@ -43,11 +42,8 @@
/** Taskbar all apps button container for customizable taskbar. */
class TaskbarAllAppsButtonContainer
@JvmOverloads
-constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
-) : IconButtonView(context, attrs), TaskbarContainer {
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+ IconButtonView(context, attrs), TaskbarContainer {
private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
private var allAppsTouchTriggered = false
@@ -101,23 +97,16 @@
private fun getAllAppsButton(isTransientTaskbar: Boolean): Int {
val shouldSelectTransientIcon =
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 {
- if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_button
- else R.drawable.ic_taskbar_all_apps_button
- }
+ return if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button
+ else R.drawable.ic_taskbar_all_apps_search_button
}
@DimenRes
fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int {
return if (isTransientTaskbar) {
R.dimen.transient_taskbar_all_apps_button_translation_x_offset
- } 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
+ R.dimen.taskbar_all_apps_search_button_translation_x_offset
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index d6ea653..1f5cd3a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -200,6 +200,8 @@
import com.android.systemui.unfold.updates.RotationChangeProvider;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import kotlin.Unit;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -212,8 +214,6 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
-import kotlin.Unit;
-
public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
SystemShortcut.BubbleActivityStarter {
private static final boolean TRACE_LAYOUTS =
@@ -692,9 +692,7 @@
}
addMultiWindowModeChangedListener(mDepthController);
initUnfoldTransitionProgressProvider();
- if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
- mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
- }
+ mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE);
QuickstepOnboardingPrefs.setup(this);
View.setTraceLayoutSteps(TRACE_LAYOUTS);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 1ba784b..18d717f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -50,9 +50,11 @@
return super.getVerticalProgress(launcher);
}
RecentsView recentsView = launcher.getOverviewPanel();
- int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher,
+ int transitionLength = LayoutUtils.getShelfTrackingDistance(
+ launcher,
launcher.getDeviceProfile(),
- recentsView.getPagedOrientationHandler());
+ recentsView.getPagedOrientationHandler(),
+ recentsView.getSizeStrategy());
AllAppsTransitionController controller = launcher.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 0da7b2d..9164405 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -129,7 +129,10 @@
mRecentsView = mLauncher.getOverviewPanel();
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
mYRange = LayoutUtils.getShelfTrackingDistance(
- mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
+ mLauncher,
+ mLauncher.getDeviceProfile(),
+ mRecentsView.getPagedOrientationHandler(),
+ mRecentsView.getSizeStrategy());
mMaxYProgress = mLauncher.getDeviceProfile().heightPx / mYRange;
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index b6a0ab3..b562838 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -142,8 +142,11 @@
.createPlaybackController();
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
RecentsView recentsView = mLauncher.getOverviewPanel();
- totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
- mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler());
+ totalShift = LayoutUtils.getShelfTrackingDistance(
+ mLauncher,
+ mLauncher.getDeviceProfile(),
+ recentsView.getPagedOrientationHandler(),
+ recentsView.getSizeStrategy());
} else {
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, config);
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 5308436..85312e4 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -76,7 +76,7 @@
&& DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
- return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
+ return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler, this);
}
}
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 360c216..1124aac 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -27,7 +27,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.ComponentCallbacks;
import android.content.res.Configuration;
@@ -38,7 +37,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.view.Choreographer;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -63,7 +61,7 @@
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.BackAnimState;
import com.android.systemui.shared.system.QuickStepContract;
import java.lang.ref.WeakReference;
@@ -109,8 +107,6 @@
private RemoteAnimationTarget mLauncherTarget;
private View mLauncherTargetView;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
- private boolean mSpringAnimationInProgress = false;
- private boolean mAnimatorSetInProgress = false;
private float mBackProgress = 0;
private boolean mBackInProgress = false;
private OnBackInvokedCallbackStub mBackCallback;
@@ -448,14 +444,15 @@
mQuickstepTransitionManager.transferRectToTargetCoordinate(
mBackTarget, mCurrentRect, true, resolveRectF);
- Pair<RectFSpringAnim, AnimatorSet> pair =
+ BackAnimState backAnim =
mQuickstepTransitionManager.createWallpaperOpenAnimations(
new RemoteAnimationTarget[]{mBackTarget},
new RemoteAnimationTarget[0],
+ new RemoteAnimationTarget[0],
resolveRectF,
cornerRadius,
mBackInProgress /* fromPredictiveBack */);
- startTransitionAnimations(pair.first, pair.second);
+ startTransitionAnimations(backAnim);
mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
customizeStatusBarAppearance(true);
}
@@ -470,8 +467,6 @@
mCurrentRect.setEmpty();
mStartRect.setEmpty();
mInitialTouchPos.set(0, 0);
- mAnimatorSetInProgress = false;
- mSpringAnimationInProgress = false;
setLauncherTargetViewVisible(true);
mLauncherTargetView = null;
// We don't call customizeStatusBarAppearance here to prevent the status bar update with
@@ -494,27 +489,8 @@
}
}
- private void startTransitionAnimations(RectFSpringAnim springAnim, AnimatorSet anim) {
- mAnimatorSetInProgress = anim != null;
- mSpringAnimationInProgress = springAnim != null;
- if (springAnim != null) {
- springAnim.addAnimatorListener(
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSpringAnimationInProgress = false;
- tryFinishBackAnimation();
- }
- }
- );
- }
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimatorSetInProgress = false;
- tryFinishBackAnimation();
- }
- });
+ private void startTransitionAnimations(BackAnimState backAnim) {
+ backAnim.addOnAnimCompleteCallback(this::finishAnimation);
if (mScrimLayer == null) {
// Scrim hasn't been attached yet. Let's attach it.
addScrimLayer();
@@ -534,7 +510,7 @@
}
});
mScrimAlphaAnimator.setDuration(SCRIM_FADE_DURATION).start();
- anim.start();
+ backAnim.start();
}
private void loadResources() {
@@ -567,12 +543,6 @@
mScrimAlpha = 0;
}
- private void tryFinishBackAnimation() {
- if (!mSpringAnimationInProgress && !mAnimatorSetInProgress) {
- finishAnimation();
- }
- }
-
private void customizeStatusBarAppearance(boolean overridingStatusBarFlags) {
if (mOverridingStatusBarFlags == overridingStatusBarFlags) {
return;
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index c1f9963..f92c557 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -29,7 +29,6 @@
import com.android.internal.jank.Cuj
import com.android.launcher3.Flags.enableOverviewCommandHelperTimeout
import com.android.launcher3.PagedView
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.logger.LauncherAtom
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON
@@ -248,7 +247,7 @@
recents: RecentsView<*, *>,
taskView: TaskView?,
command: CommandInfo,
- onCallbackResult: () -> Unit
+ onCallbackResult: () -> Unit,
): Boolean {
var callbackList: RunnableList? = null
if (taskView != null) {
@@ -274,15 +273,14 @@
private fun executeWhenRecentsIsNotVisible(
command: CommandInfo,
- onCallbackResult: () -> Unit
+ onCallbackResult: () -> Unit,
): Boolean {
val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer
val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel()
val deviceProfile = recentsViewContainer?.getDeviceProfile()
val uiController = activityInterface.getTaskbarController()
val allowQuickSwitch =
- FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() &&
- uiController != null &&
+ uiController != null &&
deviceProfile != null &&
(deviceProfile.isTablet || deviceProfile.isTwoPanels)
@@ -349,13 +347,13 @@
val gestureState =
touchInteractionService.createGestureState(
GestureState.DEFAULT_STATE,
- GestureState.TrackpadGestureType.NONE
+ GestureState.TrackpadGestureType.NONE,
)
gestureState.isHandlingAtomicEvent = true
val interactionHandler =
touchInteractionService.swipeUpHandlerFactory.newHandler(
gestureState,
- command.createTime
+ command.createTime,
)
interactionHandler.setGestureEndCallback {
onTransitionComplete(command, interactionHandler, onCallbackResult)
@@ -366,7 +364,7 @@
object : RecentsAnimationCallbacks.RecentsAnimationListener {
override fun onRecentsAnimationStart(
controller: RecentsAnimationController,
- targets: RecentsAnimationTargets
+ targets: RecentsAnimationTargets,
) {
Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
@@ -418,7 +416,7 @@
private fun onTransitionComplete(
command: CommandInfo,
handler: AbsSwipeUpHandler<*, *, *>,
- onCommandResult: () -> Unit
+ onCommandResult: () -> Unit,
) {
Log.d(TAG, "switching via recents animation - onTransitionComplete: $command")
command.removeListener(handler)
@@ -434,7 +432,7 @@
Log.d(
TAG,
"next task not scheduled. First pending command type " +
- "is ${commandQueue.firstOrNull()} - command type is: $command"
+ "is ${commandQueue.firstOrNull()} - command type is: $command",
)
return
}
@@ -527,7 +525,7 @@
val type: CommandType,
var status: CommandStatus = CommandStatus.IDLE,
val createTime: Long = SystemClock.elapsedRealtime(),
- private var animationCallbacks: RecentsAnimationCallbacks? = null
+ private var animationCallbacks: RecentsAnimationCallbacks? = null,
) {
fun setAnimationCallbacks(recentsAnimationCallbacks: RecentsAnimationCallbacks) {
this.animationCallbacks = recentsAnimationCallbacks
@@ -545,7 +543,7 @@
IDLE,
PROCESSING,
COMPLETED,
- CANCELED
+ CANCELED,
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index a01ceb2..d073580 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -56,6 +56,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
@@ -76,7 +77,8 @@
private static final Executor RECENTS_MODEL_EXECUTOR = Executors.newSingleThreadExecutor(
new SimpleThreadFactory("TaskThumbnailIconCache-", THREAD_PRIORITY_BACKGROUND));
- private final List<TaskVisualsChangeListener> mThumbnailChangeListeners = new ArrayList<>();
+ private final ConcurrentLinkedQueue<TaskVisualsChangeListener> mThumbnailChangeListeners =
+ new ConcurrentLinkedQueue<>();
private final Context mContext;
private final RecentTasksList mTaskList;
@@ -239,8 +241,8 @@
public boolean onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
mThumbnailCache.updateTaskSnapShot(taskId, snapshot);
- for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) {
- Task task = mThumbnailChangeListeners.get(i).onTaskThumbnailChanged(taskId, snapshot);
+ for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) {
+ Task task = listener.onTaskThumbnailChanged(taskId, snapshot);
if (task != null) {
task.thumbnail = snapshot;
}
@@ -269,8 +271,8 @@
@Override
public void onAppIconChanged(String packageName, UserHandle user) {
mIconCache.invalidateCacheEntries(packageName, user);
- for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) {
- mThumbnailChangeListeners.get(i).onTaskIconChanged(packageName, user);
+ for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) {
+ listener.onTaskIconChanged(packageName, user);
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ce66b04..178636e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
@@ -26,11 +25,9 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
import static com.android.launcher3.Flags.useActivityOverlay;
-import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
import static com.android.launcher3.LauncherPrefs.backedUpItem;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
@@ -92,7 +89,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatedFloat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -228,7 +224,6 @@
@BinderThread
@Override
public void onTaskbarToggled() {
- if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get()) return;
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
TaskbarActivityContext activityContext =
tis.mTaskbarManager.getCurrentActivityContext();
@@ -664,13 +659,11 @@
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
mInputManager = getSystemService(InputManager.class);
- if (ENABLE_TRACKPAD_GESTURE.get()) {
- mInputManager.registerInputDeviceListener(mInputDeviceListener,
- UI_HELPER_EXECUTOR.getHandler());
- int [] inputDevices = mInputManager.getInputDeviceIds();
- for (int inputDeviceId : inputDevices) {
- mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
- }
+ mInputManager.registerInputDeviceListener(mInputDeviceListener,
+ UI_HELPER_EXECUTOR.getHandler());
+ int [] inputDevices = mInputManager.getInputDeviceIds();
+ for (int inputDeviceId : inputDevices) {
+ mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
}
mDesktopVisibilityController = new DesktopVisibilityController(this);
mTaskbarManager = new TaskbarManager(
@@ -703,7 +696,7 @@
if (mDeviceState.isButtonNavMode()
&& !mDeviceState.supportsAssistantGestureInButtonNav()
- && (!ENABLE_TRACKPAD_GESTURE.get() || mTrackpadsConnected.isEmpty())) {
+ && (mTrackpadsConnected.isEmpty())) {
return;
}
@@ -778,23 +771,14 @@
}
private PendingIntent createAllAppsPendingIntent() {
- if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- return new PendingIntent(new IIntentSender.Stub() {
- @Override
- public void send(int code, Intent intent, String resolvedType,
- IBinder allowlistToken, IIntentReceiver finishedReceiver,
- String requiredPermission, Bundle options) {
- MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps());
- }
- });
- } else {
- return PendingIntent.getActivity(
- this,
- GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
- new Intent(mOverviewComponentObserver.getHomeIntent())
- .setAction(INTENT_ACTION_ALL_APPS_TOGGLE),
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- }
+ return new PendingIntent(new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType,
+ IBinder allowlistToken, IIntentReceiver finishedReceiver,
+ String requiredPermission, Bundle options) {
+ MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps());
+ }
+ });
}
@UiThread
@@ -1271,7 +1255,7 @@
getBaseContext(), mDeviceState, mInputMonitorCompat);
}
- if (ENABLE_TRACKPAD_GESTURE.get() && mGestureState.isTrackpadGesture()
+ if (mGestureState.isTrackpadGesture()
&& canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
reasonString = newCompoundString(reasonPrefix)
.append(SUBSTRING_PREFIX)
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
new file mode 100644
index 0000000..db29636
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -0,0 +1,24 @@
+/*
+ * 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.dagger;
+
+import com.android.quickstep.logging.LoggingModule;
+
+import dagger.Module;
+
+@Module(includes = {LoggingModule.class})
+public class QuickStepModule {
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 9284e13..5ad55ae 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -184,7 +184,7 @@
if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold
&& !mGestureState.isInExtendedSlopRegion()) {
mHasPassedTaskbarNavThreshold = true;
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar(true);
}
if (dY < 0) {
@@ -287,7 +287,7 @@
// start a single unstash timeout if hovering bottom edge under the hinted taskbar.
if (!sUnstashHandler.hasMessagesOrCallbacks()) {
sUnstashHandler.postDelayed(() -> {
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar(false);
mIsStashedTaskbarHovered = false;
}, HOVER_TASKBAR_UNSTASH_TIMEOUT);
}
@@ -315,7 +315,7 @@
startStashedTaskbarHover(/* isHovered = */ true);
} else if (mBottomEdgeBounds.contains(x, y)) {
// If hover screen's bottom edge not below the stashed taskbar, unstash it.
- mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+ mTaskbarActivityContext.onSwipeToUnstashTaskbar(false);
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 1bec970..b56958a 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -62,6 +62,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
@@ -103,6 +104,9 @@
private final AnimatedFloat mSwipeProgress = new AnimatedFloat(this::onSwipeProgressUpdate);
+ private final InvariantDeviceProfile.OnIDPChangeListener mOnIDPChangeListener =
+ modelPropertiesChanged -> updateHint();
+
private TISBindHelper mTISBindHelper;
private BgDrawable mBackground;
@@ -115,6 +119,8 @@
private AnimatorPlaybackController mLauncherStartAnim = null;
+ private TextView mHintView;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -167,12 +173,9 @@
}
});
- TextView hint = findViewById(R.id.hint);
- DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
- if (!dp.isGestureMode) {
- hint.setText(R.string.allset_button_hint);
- }
- hint.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
+ mHintView = findViewById(R.id.hint);
+ mHintView.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
+ updateHint();
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
@@ -190,7 +193,21 @@
LOTTIE_TERTIARY_COLOR_TOKEN, R.color.all_set_bg_tertiary),
getTheme());
- startBackgroundAnimation(dp.isTablet);
+ startBackgroundAnimation(getDP().isTablet);
+ getIDP().addOnChangeListener(mOnIDPChangeListener);
+ }
+
+ private InvariantDeviceProfile getIDP() {
+ return LauncherAppState.getInstance(this).getInvariantDeviceProfile();
+ }
+
+ private DeviceProfile getDP() {
+ return getIDP().getDeviceProfile(this);
+ }
+
+ private void updateHint() {
+ mHintView.setText(
+ getDP().isGestureMode ? R.string.allset_hint : R.string.allset_button_hint);
}
private void runOnUiHelperThread(Runnable runnable) {
@@ -311,6 +328,7 @@
@Override
protected void onDestroy() {
super.onDestroy();
+ getIDP().removeOnChangeListener(mOnIDPChangeListener);
mTISBindHelper.onDestroy();
clearBinderOverride();
if (mBackgroundAnimatorListener != null) {
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 742b0fc..7a86db3 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -175,11 +173,8 @@
void setFakeTaskViewFillColor(@ColorInt int colorResId) {
mFullTaskView.setBackgroundColor(colorResId);
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()){
- mTopTaskView.getBackground().setTint(colorResId);
- mBottomTaskView.getBackground().setTint(colorResId);
- }
+ mTopTaskView.getBackground().setTint(colorResId);
+ mBottomTaskView.getBackground().setTint(colorResId);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 6757cd8..be7f8e5 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION;
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
@@ -40,35 +39,29 @@
BackGestureTutorialController(BackGestureTutorialFragment fragment, TutorialType tutorialType) {
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Back gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack,
- ".surfaceBack", fragment.mRootView.mColorSurfaceBack,
- ".secondaryBack", fragment.mRootView.mColorSecondaryBack));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack,
+ ".surfaceBack", fragment.mRootView.mColorSurfaceBack,
+ ".secondaryBack", fragment.mRootView.mColorSecondaryBack));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceBack
- : fragment.mRootView.mColorSecondaryBack,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceBack
+ : fragment.mRootView.mColorSecondaryBack,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_tutorial_title
- : R.string.back_gesture_intro_title;
+ return R.string.back_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_tutorial_subtitle
- : R.string.back_gesture_intro_subtitle;
+ return R.string.back_gesture_tutorial_subtitle;
}
@Override
@@ -85,9 +78,7 @@
public int getSuccessFeedbackSubtitle() {
return mTutorialFragment.isAtFinalStep()
? R.string.back_gesture_feedback_complete_without_follow_up
- : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.back_gesture_feedback_complete_with_follow_up
- : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+ : R.string.back_gesture_feedback_complete_with_follow_up;
}
@Override
@@ -128,20 +119,12 @@
@LayoutRes
int getMockAppTaskCurrentPageLayoutResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.back_gesture_tutorial_background
- : mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_conversation
- : R.layout.gesture_tutorial_mock_conversation;
+ return R.layout.back_gesture_tutorial_background;
}
@LayoutRes
int getMockAppTaskPreviousPageLayoutResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.back_gesture_tutorial_background
- : mTutorialFragment.isLargeScreen()
- ? R.layout.gesture_tutorial_tablet_mock_conversation_list
- : R.layout.gesture_tutorial_mock_conversation_list;
+ return R.layout.back_gesture_tutorial_background;
}
@Override
@@ -214,17 +197,13 @@
}
private void handleBackAttempt(BackGestureResult result) {
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- resetViewsForBackGesture();
- }
+ resetViewsForBackGesture();
switch (result) {
case BACK_COMPLETED_FROM_LEFT:
case BACK_COMPLETED_FROM_RIGHT:
mTutorialFragment.releaseFeedbackAnimation();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mExitingAppView.setVisibility(View.GONE);
- }
+ mExitingAppView.setVisibility(View.GONE);
updateFakeAppTaskViewLayout(getMockAppTaskPreviousPageLayoutResId());
showSuccessFeedback();
break;
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
index 1b12be8..700fbf8 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
@@ -211,10 +209,8 @@
}
}
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x,
- ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel());
- }
+ mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x,
+ ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel());
// forward touch
mEdgeBackPanel.onMotionEvent(ev);
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index acc9959..bc5cc15 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -37,7 +37,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.interaction.TutorialController.TutorialType;
@@ -79,9 +78,7 @@
Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
boolean gestureComplete = args != null && args.getBoolean(KEY_GESTURE_COMPLETE, false);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- && args != null
- && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) {
+ if (args != null && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) {
mTutorialSteps = null;
TutorialType tutorialTypeOverride = (TutorialType) args.get(KEY_TUTORIAL_TYPE);
mCurrentFragment = tutorialTypeOverride == null
@@ -101,9 +98,7 @@
.add(R.id.gesture_tutorial_fragment_container, mCurrentFragment)
.commit();
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- correctUserOrientation();
- }
+ correctUserOrientation();
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
initWindowInsets();
@@ -115,9 +110,7 @@
super.onConfigurationChanged(newConfig);
// Ensure the prompt to rotate the screen is updated
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- correctUserOrientation();
- }
+ correctUserOrientation();
}
private void initWindowInsets() {
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 1129e02..bf4eaf2 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.graphics.PointF;
import com.android.launcher3.R;
@@ -34,35 +32,29 @@
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Home gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome,
- ".surfaceHome", fragment.mRootView.mColorSurfaceHome,
- ".secondaryHome", fragment.mRootView.mColorSecondaryHome));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome,
+ ".surfaceHome", fragment.mRootView.mColorSurfaceHome,
+ ".secondaryHome", fragment.mRootView.mColorSecondaryHome));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceHome
- : fragment.mRootView.mColorSecondaryHome,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceHome
+ : fragment.mRootView.mColorSecondaryHome,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_title
- : R.string.home_gesture_intro_title;
+ return R.string.home_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_subtitle
- : R.string.home_gesture_intro_subtitle;
+ return R.string.home_gesture_tutorial_subtitle;
}
@Override
@@ -72,9 +64,7 @@
@Override
public int getSuccessFeedbackTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.home_gesture_tutorial_success
- : R.string.gesture_tutorial_nice;
+ return R.string.home_gesture_tutorial_success;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index a04dd44..e45f8d8 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.interaction;
import static com.android.app.animation.Interpolators.ACCELERATE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -49,34 +48,28 @@
super(fragment, tutorialType);
// Set the Lottie animation colors specifically for the Overview gesture
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- LottieAnimationColorUtils.updateToArgbColors(
- mAnimatedGestureDemonstration,
- Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview,
- ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview,
- ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview));
+ LottieAnimationColorUtils.updateToArgbColors(
+ mAnimatedGestureDemonstration,
+ Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview,
+ ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview,
+ ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview));
- LottieAnimationColorUtils.updateToArgbColors(
- mCheckmarkAnimation,
- Map.of(".checkmark",
- Utilities.isDarkTheme(mContext)
- ? fragment.mRootView.mColorOnSurfaceOverview
- : fragment.mRootView.mColorSecondaryOverview,
- ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview));
- }
+ LottieAnimationColorUtils.updateToArgbColors(
+ mCheckmarkAnimation,
+ Map.of(".checkmark",
+ Utilities.isDarkTheme(mContext)
+ ? fragment.mRootView.mColorOnSurfaceOverview
+ : fragment.mRootView.mColorSecondaryOverview,
+ ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview));
}
@Override
public int getIntroductionTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_title
- : R.string.overview_gesture_intro_title;
+ return R.string.overview_gesture_tutorial_title;
}
@Override
public int getIntroductionSubtitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_subtitle
- : R.string.overview_gesture_intro_subtitle;
+ return R.string.overview_gesture_tutorial_subtitle;
}
@Override
@@ -86,9 +79,7 @@
@Override
public int getSuccessFeedbackTitle() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.string.overview_gesture_tutorial_success
- : R.string.gesture_tutorial_nice;
+ return R.string.overview_gesture_tutorial_success;
}
@Override
@@ -168,10 +159,7 @@
@Override
protected int getMockPreviousAppTaskThumbnailColor() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? mTutorialFragment.mRootView.mColorSurfaceContainer
- : mContext.getResources().getColor(
- R.color.gesture_tutorial_fake_previous_task_view_color);
+ return mTutorialFragment.mRootView.mColorSurfaceContainer;
}
@Override
@@ -224,11 +212,8 @@
case OVERVIEW_GESTURE_COMPLETED:
setGestureCompleted();
mTutorialFragment.releaseFeedbackAnimation();
- animateTaskViewToOverview(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get());
+ animateTaskViewToOverview(true);
onMotionPaused(true /*arbitrary value*/);
- if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- showSuccessFeedback();
- }
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
case HOME_OR_OVERVIEW_CANCELLED:
diff --git a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
index affedb9..d733267 100644
--- a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
+++ b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java
@@ -15,16 +15,12 @@
*/
package com.android.quickstep.interaction;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.View;
import android.view.WindowInsets;
import android.widget.RelativeLayout;
@@ -39,10 +35,6 @@
/** Root layout that TutorialFragment uses to intercept motion events. */
public class RootSandboxLayout extends RelativeLayout {
- private final Rect mTempStepIndicatorBounds = new Rect();
- private final Rect mTempInclusionBounds = new Rect();
- private final Rect mTempExclusionBounds = new Rect();
-
@ColorInt final int mColorSurfaceContainer;
@ColorInt final int mColorOnSurfaceHome;
@ColorInt final int mColorSurfaceHome;
@@ -54,11 +46,6 @@
@ColorInt final int mColorSurfaceOverview;
@ColorInt final int mColorSecondaryOverview;
- private View mFeedbackView;
- private View mTutorialStepView;
- private View mSkipButton;
- private View mDoneButton;
-
public RootSandboxLayout(Context context) {
this(context, null);
}
@@ -123,56 +110,4 @@
return getHeight() + insets.top + insets.bottom;
}
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- return;
- }
- mFeedbackView = findViewById(R.id.gesture_tutorial_fragment_feedback_view);
- mTutorialStepView =
- mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step);
- mSkipButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_close_button);
- mDoneButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_action_button);
-
- mFeedbackView.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- if (mSkipButton.getVisibility() != VISIBLE
- && mDoneButton.getVisibility() != VISIBLE) {
- return;
- }
- // Either the skip or the done button is ever shown at once, never both.
- boolean showingSkipButton = mSkipButton.getVisibility() == VISIBLE;
- boolean isRTL = Utilities.isRtl(getContext().getResources());
- updateTutorialStepViewTranslation(
- showingSkipButton ? mSkipButton : mDoneButton,
- // Translate the step indicator away from whichever button is being
- // shown. The skip button in on the left in LTR or on the right in RTL.
- // The done button is on the right in LTR or left in RTL.
- (showingSkipButton && !isRTL) || (!showingSkipButton && isRTL));
- });
- }
-
- private void updateTutorialStepViewTranslation(
- @NonNull View anchorView, boolean translateToRight) {
- mTempStepIndicatorBounds.set(
- mTutorialStepView.getLeft(),
- mTutorialStepView.getTop(),
- mTutorialStepView.getRight(),
- mTutorialStepView.getBottom());
- mTempInclusionBounds.set(0, 0, mFeedbackView.getWidth(), mFeedbackView.getHeight());
- mTempExclusionBounds.set(
- anchorView.getLeft(),
- anchorView.getTop(),
- anchorView.getRight(),
- anchorView.getBottom());
-
- Utilities.translateOverlappingView(
- mTutorialStepView,
- mTempStepIndicatorBounds,
- mTempInclusionBounds,
- mTempExclusionBounds,
- translateToRight ? Utilities.TRANSLATE_RIGHT : Utilities.TRANSLATE_LEFT);
- }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index ad13efb..e462706 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -48,7 +48,6 @@
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsAnimationDeviceState;
@@ -127,9 +126,7 @@
void resetTaskViews() {
mFakeHotseatView.setVisibility(View.INVISIBLE);
mFakeIconView.setVisibility(View.INVISIBLE);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFakeIconView.getBackground().setTint(getFakeTaskViewColor());
- }
+ mFakeIconView.getBackground().setTint(getFakeTaskViewColor());
if (mTutorialFragment.getActivity() != null) {
int height = mTutorialFragment.getRootView().getFullscreenHeight();
int width = mTutorialFragment.getRootView().getWidth();
@@ -138,9 +135,7 @@
mFakeTaskViewRadius = 0;
mFakeTaskView.invalidateOutline();
mFakeTaskView.setVisibility(View.VISIBLE);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
- }
+ mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
mFakeTaskView.setAlpha(1);
mFakePreviousTaskView.setVisibility(View.INVISIBLE);
mFakePreviousTaskView.setAlpha(1);
@@ -390,12 +385,10 @@
false, /* isOpening */
mFakeIconView, mDp);
mFakeIconView.setAlpha(1);
- if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- int iconColor = ColorUtils.blendARGB(
- getFakeTaskViewColor(), getHotseatIconColor(), progress);
- mFakeIconView.getBackground().setTint(iconColor);
- mFakeTaskView.setBackgroundColor(iconColor);
- }
+ int iconColor = ColorUtils.blendARGB(
+ getFakeTaskViewColor(), getHotseatIconColor(), progress);
+ mFakeIconView.getBackground().setTint(iconColor);
+ mFakeTaskView.setBackgroundColor(iconColor);
mFakeTaskView.setAlpha(getWindowAlpha(progress));
mFakePreviousTaskView.setAlpha(getWindowAlpha(progress));
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 54653fa..5028da4 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -19,10 +19,7 @@
import static android.view.View.NO_ID;
import static android.view.View.inflate;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
-
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -33,7 +30,6 @@
import android.graphics.Matrix;
import android.graphics.Outline;
import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.Log;
@@ -52,7 +48,6 @@
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
@@ -153,8 +148,7 @@
mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view);
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
- mFakeTaskbarView = ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? null : rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view);
+ mFakeTaskbarView = null;
mFakePreviousTaskView =
rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
@@ -165,32 +159,30 @@
mFingerDotView = rootView.findViewById(R.id.gesture_tutorial_finger_dot);
mSkipTutorialDialog = createSkipTutorialDialog();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration);
- mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation);
- mAnimatedGestureDemonstration = rootView.findViewById(
- R.id.gesture_demonstration_animations);
- mExitingAppView = rootView.findViewById(R.id.exiting_app_back);
- mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx;
- mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx;
- mExitingAppMargin = mContext.getResources().getDimensionPixelSize(
- R.dimen.gesture_tutorial_back_gesture_exiting_app_margin);
- mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext);
- mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize(
- R.dimen.gesture_tutorial_back_gesture_end_corner_radius);
- mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener(
- this::createScalingMatrix);
+ mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration);
+ mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation);
+ mAnimatedGestureDemonstration = rootView.findViewById(
+ R.id.gesture_demonstration_animations);
+ mExitingAppView = rootView.findViewById(R.id.exiting_app_back);
+ mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx;
+ mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx;
+ mExitingAppMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.gesture_tutorial_back_gesture_exiting_app_margin);
+ mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext);
+ mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize(
+ R.dimen.gesture_tutorial_back_gesture_end_corner_radius);
+ mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener(
+ this::createScalingMatrix);
- mFeedbackTitleView.setText(getIntroductionTitle());
- mFeedbackSubtitleView.setText(getIntroductionSubtitle());
- mExitingAppView.setClipToOutline(true);
- mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(mExitingAppRect, mExitingAppRadius);
- }
- });
- }
+ mFeedbackTitleView.setText(getIntroductionTitle());
+ mFeedbackSubtitleView.setText(getIntroductionSubtitle());
+ mExitingAppView.setClipToOutline(true);
+ mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(mExitingAppRect, mExitingAppRadius);
+ }
+ });
mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
AccessibilityEvent.TYPE_VIEW_FOCUSED);
@@ -261,19 +253,11 @@
@LayoutRes
protected int getMockHotseatResId() {
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- return mTutorialFragment.isLargeScreen()
- ? mTutorialFragment.isFoldable()
- ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat
- : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat
- : R.layout.redesigned_gesture_tutorial_mock_hotseat;
- } else {
- return mTutorialFragment.isLargeScreen()
- ? mTutorialFragment.isFoldable()
- ? R.layout.gesture_tutorial_foldable_mock_hotseat
- : R.layout.gesture_tutorial_tablet_mock_hotseat
- : R.layout.gesture_tutorial_mock_hotseat;
- }
+ return mTutorialFragment.isLargeScreen()
+ ? mTutorialFragment.isFoldable()
+ ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat
+ : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat
+ : R.layout.redesigned_gesture_tutorial_mock_hotseat;
}
@LayoutRes
@@ -312,9 +296,7 @@
@DrawableRes
public int getMockAppIconResId() {
- return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.drawable.redesigned_hotseat_icon
- : R.drawable.default_sandbox_app_icon;
+ return R.drawable.redesigned_hotseat_icon;
}
@DrawableRes
@@ -374,11 +356,7 @@
mFeedbackView.setTranslationY(0);
return;
}
- Animator gestureAnimation = mTutorialFragment.getGestureAnimation();
- AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation();
- if (gestureAnimation != null && edgeAnimation != null) {
- playFeedbackAnimation(gestureAnimation, edgeAnimation, mShowFeedbackRunnable, true);
- }
+ playFeedbackAnimation();
}
/**
@@ -442,12 +420,7 @@
}
mFeedbackTitleView.setText(titleResId);
- mFeedbackSubtitleView.setText(
- ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() || spokenSubtitleResId == NO_ID
- ? mContext.getText(subtitleResId)
- : Utilities.wrapForTts(
- mContext.getText(subtitleResId),
- mContext.getString(spokenSubtitleResId)));
+ mFeedbackSubtitleView.setText(subtitleResId);
if (isGestureSuccessful) {
if (mTutorialFragment.isAtFinalStep()) {
showActionButton();
@@ -458,27 +431,16 @@
mFakeTaskViewCallback = null;
}
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- showSuccessPage();
- }
+ showSuccessPage();
}
mGestureCompleted = isGestureSuccessful;
-
- Animator gestureAnimation = mTutorialFragment.getGestureAnimation();
- AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation();
- if (!isGestureSuccessful && gestureAnimation != null && edgeAnimation != null) {
- playFeedbackAnimation(
- gestureAnimation,
- edgeAnimation,
- mShowFeedbackRunnable,
- useGestureAnimationDelay);
- return;
+ if (!isGestureSuccessful) {
+ playFeedbackAnimation();
} else {
mTutorialFragment.releaseFeedbackAnimation();
+ mFeedbackViewCallback = mShowFeedbackRunnable;
+ mFeedbackView.post(mFeedbackViewCallback);
}
- mFeedbackViewCallback = mShowFeedbackRunnable;
-
- mFeedbackView.post(mFeedbackViewCallback);
}
private void showSuccessPage() {
@@ -517,79 +479,17 @@
mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
}
- private void playFeedbackAnimation(
- @NonNull Animator gestureAnimation,
- @NonNull AnimatedVectorDrawable edgeAnimation,
- @NonNull Runnable onStartRunnable,
- boolean useGestureAnimationDelay) {
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFeedbackView.setVisibility(View.VISIBLE);
- mAnimatedGestureDemonstration.setVisibility(View.VISIBLE);
- mFullGestureDemonstration.setVisibility(View.VISIBLE);
- mAnimatedGestureDemonstration.playAnimation();
- return;
- }
-
- if (gestureAnimation.isRunning()) {
- gestureAnimation.cancel();
- }
- if (edgeAnimation.isRunning()) {
- edgeAnimation.reset();
- }
- gestureAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
-
- mEdgeGestureVideoView.setVisibility(GONE);
- if (edgeAnimation.isRunning()) {
- edgeAnimation.stop();
- }
-
- if (!useGestureAnimationDelay) {
- onStartRunnable.run();
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
-
- mEdgeGestureVideoView.setVisibility(View.VISIBLE);
- edgeAnimation.start();
-
- gestureAnimation.removeListener(this);
- }
- });
-
- cancelQueuedGestureAnimation();
- if (useGestureAnimationDelay) {
- mFeedbackViewCallback = onStartRunnable;
- mFakeTaskViewCallback = gestureAnimation::start;
-
- mFeedbackView.post(mFeedbackViewCallback);
- mFakeTaskView.postDelayed(mFakeTaskViewCallback, GESTURE_ANIMATION_DELAY_MS);
- } else {
- gestureAnimation.start();
- }
+ private void playFeedbackAnimation() {
+ mFeedbackView.setVisibility(View.VISIBLE);
+ mAnimatedGestureDemonstration.setVisibility(View.VISIBLE);
+ mFullGestureDemonstration.setVisibility(View.VISIBLE);
+ mAnimatedGestureDemonstration.playAnimation();
}
void setRippleHotspot(float x, float y) {
mRippleDrawable.setHotspot(x, y);
}
- void showRippleEffect(@Nullable Runnable onCompleteRunnable) {
- mRippleDrawable.setState(
- new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled});
- mRippleView.postDelayed(() -> {
- mRippleDrawable.setState(new int[] {});
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- }, RIPPLE_VISIBLE_MS);
- }
-
void onActionButtonClicked(View button) {
mTutorialFragment.continueTutorial();
}
@@ -601,24 +501,19 @@
updateDrawables();
updateLayout();
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance());
- mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance());
- mDoneButton.getBackground().setTint(getDoneButtonColor());
- mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep()
- ? R.raw.checkmark_animation_end
- : R.raw.checkmark_animation_in_progress);
- if (!isGestureCompleted()) {
- mCheckmarkAnimation.setVisibility(GONE);
- startGestureAnimation();
- if (mTutorialType == TutorialType.BACK_NAVIGATION) {
- resetViewsForBackGesture();
- }
-
+ mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance());
+ mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance());
+ mDoneButton.getBackground().setTint(getDoneButtonColor());
+ mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep()
+ ? R.raw.checkmark_animation_end
+ : R.raw.checkmark_animation_in_progress);
+ if (!isGestureCompleted()) {
+ mCheckmarkAnimation.setVisibility(GONE);
+ startGestureAnimation();
+ if (mTutorialType == TutorialType.BACK_NAVIGATION) {
+ resetViewsForBackGesture();
}
- } else {
- hideFeedback();
- hideActionButton();
+
}
mGestureCompleted = false;
@@ -654,13 +549,6 @@
: R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark);
}
- void hideActionButton() {
- mSkipButton.setVisibility(View.VISIBLE);
- // Invisible to maintain the layout.
- mDoneButton.setVisibility(View.INVISIBLE);
- mDoneButton.setOnClickListener(null);
- }
-
void showActionButton() {
mSkipButton.setVisibility(GONE);
mDoneButton.setVisibility(View.VISIBLE);
@@ -711,10 +599,8 @@
}
private void updateSubtext() {
- if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mTutorialStepView.setTutorialProgress(
- mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
- }
+ mTutorialStepView.setTutorialProgress(
+ mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps());
}
private void updateHotseatChildViewColor(@Nullable View child) {
@@ -727,9 +613,7 @@
mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable(
mContext, getMockWallpaperResId()));
mTutorialFragment.updateFeedbackAnimation();
- mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? getFakeLauncherColor()
- : mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color));
+ mFakeLauncherView.setBackgroundColor(getFakeLauncherColor());
updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId());
mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1);
mFakeTaskView.animate().alpha(1).setListener(
@@ -738,19 +622,15 @@
mFakeIconView.setBackground(AppCompatResources.getDrawable(
mContext, getMockAppIconResId()));
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mExitingAppView.setBackgroundColor(getExitingAppColor());
- mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
- updateHotseatChildViewColor(mHotseatIconView);
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6));
- updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
- } else {
- updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
- }
+ mExitingAppView.setBackgroundColor(getExitingAppColor());
+ mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
+ updateHotseatChildViewColor(mHotseatIconView);
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6));
+ updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 0fafb94..2ff2c83 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -17,7 +17,6 @@
import static android.view.View.NO_ID;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_GESTURE_COMPLETE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU;
@@ -215,9 +214,7 @@
super.onCreateView(inflater, container, savedInstanceState);
mRootView = (RootSandboxLayout) inflater.inflate(
- ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
- ? R.layout.redesigned_gesture_tutorial_fragment
- : R.layout.gesture_tutorial_fragment,
+ R.layout.redesigned_gesture_tutorial_fragment,
container,
false);
@@ -383,10 +380,7 @@
if (mTutorialController != null && !isGestureComplete()) {
mTutorialController.hideFeedback();
}
-
- if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
- mTutorialController.pauseAndHideLottieAnimation();
- }
+ mTutorialController.pauseAndHideLottieAnimation();
// Note: Using logical-or to ensure both functions get called.
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
diff --git a/quickstep/src/com/android/quickstep/logging/LoggingModule.java b/quickstep/src/com/android/quickstep/logging/LoggingModule.java
new file mode 100644
index 0000000..8fdf3c7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/logging/LoggingModule.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.quickstep.logging;
+
+import android.content.Context;
+
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class LoggingModule {
+ @Provides
+ @LauncherAppSingleton
+ SettingsChangeLogger provideSettingsChangeLogger(@ApplicationContext Context context) {
+ return SettingsChangeLogger.INSTANCE.get(context);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
index a141e89..a45d194 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt
@@ -23,6 +23,7 @@
import com.android.quickstep.util.TaskVisualsChangeListener
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.concurrent.ConcurrentHashMap
/** Delegates the checking of task visuals (thumbnails, high res changes, icons) */
interface TaskVisualsChangedDelegate :
@@ -30,7 +31,7 @@
/** Registers a callback for visuals relating to icons */
fun registerTaskIconChangedCallback(
taskKey: Task.TaskKey,
- taskIconChangedCallback: TaskIconChangedCallback
+ taskIconChangedCallback: TaskIconChangedCallback,
)
/** Unregisters a callback for visuals relating to icons */
@@ -39,7 +40,7 @@
/** Registers a callback for visuals relating to thumbnails */
fun registerTaskThumbnailChangedCallback(
taskKey: Task.TaskKey,
- taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback,
)
/** Unregisters a callback for visuals relating to thumbnails */
@@ -66,31 +67,9 @@
private val highResLoadingStateNotifier: HighResLoadingStateNotifier,
) : TaskVisualsChangedDelegate {
private val taskIconChangedCallbacks =
- mutableMapOf<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>()
+ ConcurrentHashMap<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
- }
+ ConcurrentHashMap<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>()
override fun onTaskIconChanged(taskId: Int) {
taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() }
@@ -119,27 +98,48 @@
override fun registerTaskIconChangedCallback(
taskKey: Task.TaskKey,
- taskIconChangedCallback: TaskIconChangedCallback
+ taskIconChangedCallback: TaskIconChangedCallback,
) {
- taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
- onCallbackRegistered()
+ updateCallbacks {
+ taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback
+ }
}
override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) {
- taskIconChangedCallbacks.remove(taskKey.id)
- onCallbackUnregistered()
+ updateCallbacks { taskIconChangedCallbacks.remove(taskKey.id) }
}
override fun registerTaskThumbnailChangedCallback(
taskKey: Task.TaskKey,
- taskThumbnailChangedCallback: TaskThumbnailChangedCallback
+ taskThumbnailChangedCallback: TaskThumbnailChangedCallback,
) {
- taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
- onCallbackRegistered()
+ updateCallbacks {
+ taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback
+ }
}
override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) {
- taskThumbnailChangedCallbacks.remove(taskKey.id)
- onCallbackUnregistered()
+ updateCallbacks { taskThumbnailChangedCallbacks.remove(taskKey.id) }
+ }
+
+ @Synchronized
+ private fun updateCallbacks(callbackModifier: () -> Unit) {
+ val prevHasCallbacks =
+ taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0
+ callbackModifier()
+
+ val currHasCallbacks =
+ taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0
+
+ when {
+ prevHasCallbacks && !currHasCallbacks -> {
+ taskVisualsChangeNotifier.removeThumbnailChangeListener(this)
+ highResLoadingStateNotifier.removeCallback(this)
+ }
+ !prevHasCallbacks && currHasCallbacks -> {
+ taskVisualsChangeNotifier.addThumbnailChangeListener(this)
+ highResLoadingStateNotifier.addCallback(this)
+ }
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
index 1716f2e..5cf6823 100644
--- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
+++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt
@@ -24,7 +24,7 @@
class RecentsViewModel(
private val recentsTasksRepository: RecentTasksRepository,
- private val recentsViewData: RecentsViewData
+ private val recentsViewData: RecentsViewData,
) {
fun refreshAllTaskData() {
recentsTasksRepository.getAllTaskData(true)
@@ -58,7 +58,8 @@
recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha
}
- suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) {
+ suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>?) {
+ if (updatedThumbnails.isNullOrEmpty()) return
combine(
updatedThumbnails.map {
recentsTasksRepository.getThumbnailById(it.key).filter { thumbnailData ->
diff --git a/quickstep/src/com/android/quickstep/util/BackAnimState.kt b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
new file mode 100644
index 0000000..9009eaa
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BackAnimState.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.animation.AnimatorSet
+import android.content.Context
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.RunnableList
+
+/** Interface to represent animation for back to Launcher transition */
+interface BackAnimState {
+
+ fun addOnAnimCompleteCallback(r: Runnable)
+
+ fun applyToAnimationResult(result: AnimationResult, c: Context)
+
+ fun start()
+}
+
+class AnimatorBackState(private val springAnim: RectFSpringAnim?, private val anim: AnimatorSet?) :
+ BackAnimState {
+
+ override fun addOnAnimCompleteCallback(r: Runnable) {
+ val springAnimWait = RunnableList()
+ springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy))
+ ?: springAnimWait.executeAllAndDestroy()
+
+ val animWait = RunnableList()
+ anim?.addListener(
+ forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) })
+ ) ?: springAnimWait.add(animWait::executeAllAndDestroy)
+ animWait.add(r)
+ }
+
+ override fun applyToAnimationResult(result: AnimationResult, c: Context) {
+ result.setAnimation(anim, c)
+ }
+
+ override fun start() {
+ anim?.start()
+ }
+}
+
+class AlreadyStartedBackAnimState(private val onEndCallback: RunnableList) : BackAnimState {
+
+ override fun addOnAnimCompleteCallback(r: Runnable) {
+ onEndCallback.add(r)
+ }
+
+ override fun applyToAnimationResult(result: AnimationResult, c: Context) {
+ addOnAnimCompleteCallback(result::onAnimationFinished)
+ }
+
+ override fun start() {}
+}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 26668c8..4c26761 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -31,7 +31,6 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.quickstep.SystemUiProxy;
@@ -80,17 +79,12 @@
@UnfoldMain RotationChangeProvider rotationChangeProvider) {
mLauncher = launcher;
- if (FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider(
- unfoldTransitionProgressProvider, launcher.getMainThreadHandler());
- mPreemptiveProgressProvider.init();
+ mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider(
+ unfoldTransitionProgressProvider, launcher.getMainThreadHandler());
+ mPreemptiveProgressProvider.init();
- mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
- mPreemptiveProgressProvider);
- } else {
- mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
- unfoldTransitionProgressProvider);
- }
+ mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
+ mPreemptiveProgressProvider);
unfoldTransitionProgressProvider.addCallback(mExternalTransitionStatusProvider);
unfoldTransitionProgressProvider.addCallback(
@@ -169,10 +163,6 @@
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
- if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- return;
- }
-
if (mIsTablet != null && dp.isTablet != mIsTablet) {
// We should preemptively start the animation only if:
// - We changed to the unfolded screen
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index b9338a3..a8460c9 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -23,7 +23,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
-import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
public class LayoutUtils {
@@ -41,11 +41,14 @@
return swipeHeight;
}
- public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
- RecentsPagedOrientationHandler orientationHandler) {
+ public static int getShelfTrackingDistance(
+ Context context,
+ DeviceProfile dp,
+ RecentsPagedOrientationHandler orientationHandler,
+ BaseContainerInterface<?, ?> baseContainerInterface) {
// Track the bottom of the window.
Rect taskSize = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
+ baseContainerInterface.calculateTaskSize(context, dp, taskSize,
orientationHandler);
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index c3270dc..f3b984b8 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.util;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.Display.DEFAULT_DISPLAY;
import android.content.Context;
@@ -30,6 +31,8 @@
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
+import com.android.quickstep.SystemUiProxy;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.util.List;
import java.util.Set;
@@ -66,6 +69,24 @@
}
@Override
+ public boolean showLockedTaskbarOnHome(Context displayInfoContext) {
+ if (!DesktopModeStatus.canEnterDesktopMode(displayInfoContext)) {
+ return false;
+ }
+ if (!DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(displayInfoContext)) {
+ return false;
+ }
+ final boolean isFreeformDisplay = displayInfoContext.getResources().getConfiguration()
+ .windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
+ return isFreeformDisplay;
+ }
+
+ @Override
+ public boolean isHomeVisible(Context context) {
+ return SystemUiProxy.INSTANCE.get(context).getHomeVisibilityState().isHomeVisible();
+ }
+
+ @Override
public int getRotation(Context displayInfoContext) {
return displayInfoContext.getResources().getConfiguration().windowConfiguration
.getRotation();
diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
index 09563f5..915c9e5 100644
--- a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
+++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
@@ -22,7 +22,6 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
import com.android.launcher3.anim.PendingAnimation
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.uioverrides.QuickstepLauncher
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
@@ -30,7 +29,7 @@
/** Controls animations that are happening during unfolding foldable devices */
class LauncherUnfoldTransitionController(
private val launcher: QuickstepLauncher,
- private val progressProvider: ProxyUnfoldTransitionProvider
+ private val progressProvider: ProxyUnfoldTransitionProvider,
) : OnDeviceProfileChangeListener, ActivityLifecycleCallbacksAdapter, TransitionProgressListener {
private var isTablet: Boolean? = null
@@ -57,10 +56,6 @@
}
override fun onDeviceProfileChanged(dp: DeviceProfile) {
- if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
- return
- }
-
if (isTablet != null && dp.isTablet != isTablet) {
// We should preemptively start the animation only if:
// - We changed to the unfolded screen
@@ -93,7 +88,7 @@
provider = this,
factory = this::onPrepareUnfoldAnimation,
duration =
- 1000L // The expected duration for the animation. Then only comes to play if we have
+ 1000L, // The expected duration for the animation. Then only comes to play if we have
// to run the animation ourselves in case sysui misses the end signal
)
timeoutAlarm.cancelAlarm()
@@ -119,7 +114,7 @@
launcher,
isVertical,
dp.displayInfo.currentSize,
- anim
+ anim,
)
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index 4604b70..f22c672 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -49,9 +49,7 @@
recentsViewModel.setRunningTaskShowScreenshot(true)
viewAttachedScope.launch {
recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
- if (updatedThumbnails != null) {
- recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails)
- }
+ recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails)
ViewUtils.postFrameDrawn(taskView, onFinishRunnable)
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 4dcf2e7..2ed6ae6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -46,7 +46,6 @@
import androidx.core.view.updateLayoutParams
import com.android.app.animation.Interpolators
import com.android.launcher3.Flags.enableCursorHoverStates
-import com.android.launcher3.Flags.enableFocusOutline
import com.android.launcher3.Flags.enableGridOnlyOverview
import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview
import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
@@ -55,7 +54,6 @@
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.anim.AnimatedFloat
-import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.testing.TestLogging
@@ -485,27 +483,23 @@
taskViewModel = RecentsDependencies.get(this, "TaskViewType" to type)
}
- val keyboardFocusHighlightEnabled =
- (ENABLE_KEYBOARD_QUICK_SWITCH.get() || enableFocusOutline())
val cursorHoverStatesEnabled = enableCursorHoverStates()
- setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled)
+ setWillNotDraw(!cursorHoverStatesEnabled)
context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use {
this.focusBorderAnimator =
focusBorderAnimator
- ?: if (keyboardFocusHighlightEnabled)
- createSimpleBorderAnimator(
- currentFullscreenParams.cornerRadius.toInt(),
- context.resources.getDimensionPixelSize(
- R.dimen.keyboard_quick_switch_border_width
- ),
- { bounds: Rect -> getThumbnailBounds(bounds) },
- this,
- it.getColor(
- R.styleable.TaskView_focusBorderColor,
- BorderAnimator.DEFAULT_BORDER_COLOR,
- ),
- )
- else null
+ ?: createSimpleBorderAnimator(
+ currentFullscreenParams.cornerRadius.toInt(),
+ context.resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_border_width
+ ),
+ { bounds: Rect -> getThumbnailBounds(bounds) },
+ this,
+ it.getColor(
+ R.styleable.TaskView_focusBorderColor,
+ BorderAnimator.DEFAULT_BORDER_COLOR,
+ ),
+ )
this.hoverBorderAnimator =
hoverBorderAnimator
?: if (cursorHoverStatesEnabled)
@@ -611,6 +605,7 @@
override fun onRecycle() {
resetPersistentViewTransforms()
+ attachAlpha = 1f
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
if (!enableRefactorTaskThumbnail()) {
@@ -1608,7 +1603,6 @@
}
dismissScale = 1f
translationZ = 0f
- attachAlpha = 1f
setIconScaleAndDim(1f)
setColorTint(0f, 0)
}
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
new file mode 100644
index 0000000..b1ff4a1
--- /dev/null
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.bubbles.flyout
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import androidx.test.core.app.ApplicationProvider
+import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.Displays
+import platform.test.screenshot.ViewScreenshotTestRule
+import platform.test.screenshot.getEmulatedDevicePathConfig
+
+/** Screenshot tests for [BubbleBarFlyoutView]. */
+@RunWith(ParameterizedAndroidJunit4::class)
+class BubbleBarFlyoutViewScreenshotTest(emulationSpec: DeviceEmulationSpec) {
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ companion object {
+ @Parameters(name = "{0}")
+ @JvmStatic
+ fun getTestSpecs() =
+ DeviceEmulationSpec.forDisplays(
+ Displays.Phone,
+ isDarkTheme = false,
+ isLandscape = false,
+ )
+ }
+
+ @get:Rule
+ val screenshotRule =
+ ViewScreenshotTestRule(
+ emulationSpec,
+ ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)),
+ )
+
+ @Test
+ fun bubbleBarFlyoutView_noAvatar() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "message",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "message",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
new file mode 100644
index 0000000..a58ce08
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.bubbles.flyout
+
+import android.content.Context
+import android.view.Gravity
+import android.widget.FrameLayout
+import android.widget.TextView
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit tests for [BubbleBarFlyoutController] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubbleBarFlyoutControllerTest {
+
+ private lateinit var flyoutController: BubbleBarFlyoutController
+ private lateinit var flyoutContainer: FrameLayout
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private val flyoutMessage =
+ BubbleBarFlyoutMessage(senderAvatar = null, "sender name", "message", isGroupChat = false)
+ private var onLeft = true
+
+ @Before
+ fun setUp() {
+ flyoutContainer = FrameLayout(context)
+ val positioner =
+ object : BubbleBarFlyoutPositioner {
+ override val isOnLeft: Boolean
+ get() = onLeft
+
+ override val targetTy: Float
+ get() = 50f
+ }
+ flyoutController = BubbleBarFlyoutController(flyoutContainer, positioner)
+ }
+
+ @Test
+ fun flyoutPosition_left() {
+ flyoutController.setUpFlyout(flyoutMessage)
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ val flyout = flyoutContainer.getChildAt(0)
+ val lp = flyout.layoutParams as FrameLayout.LayoutParams
+ assertThat(lp.gravity).isEqualTo(Gravity.BOTTOM or Gravity.LEFT)
+ assertThat(flyout.translationY).isEqualTo(50f)
+ }
+
+ @Test
+ fun flyoutPosition_right() {
+ onLeft = false
+ flyoutController.setUpFlyout(flyoutMessage)
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ val flyout = flyoutContainer.getChildAt(0)
+ val lp = flyout.layoutParams as FrameLayout.LayoutParams
+ assertThat(lp.gravity).isEqualTo(Gravity.BOTTOM or Gravity.RIGHT)
+ assertThat(flyout.translationY).isEqualTo(50f)
+ }
+
+ @Test
+ fun flyoutMessage() {
+ flyoutController.setUpFlyout(flyoutMessage)
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ val flyout = flyoutContainer.getChildAt(0)
+ val sender = flyout.findViewById<TextView>(R.id.bubble_flyout_name)
+ assertThat(sender.text).isEqualTo("sender name")
+ val message = flyout.findViewById<TextView>(R.id.bubble_flyout_text)
+ assertThat(message.text).isEqualTo("message")
+ }
+
+ @Test
+ fun hideFlyout_removedFromContainer() {
+ flyoutController.setUpFlyout(flyoutMessage)
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ flyoutController.hideFlyout()
+ assertThat(flyoutContainer.childCount).isEqualTo(0)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index 1d13956..d4a3b3a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -32,6 +32,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
+import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.launcher3.util.MultiValueAlpha
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
@@ -55,8 +56,8 @@
companion object {
const val TASKBAR_BOTTOM_SPACE = 5
- const val BUBBLE_BAR_WIDTH = 200f
- const val BUBBLE_BAR_HEIGHT = 100f
+ const val BUBBLE_BAR_WIDTH = 200
+ const val BUBBLE_BAR_HEIGHT = 100
const val HOTSEAT_TRANSLATION_Y = -45f
const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE
const val HANDLE_VIEW_WIDTH = 150
@@ -77,10 +78,12 @@
private val context = ApplicationProvider.getApplicationContext<Context>()
private lateinit var bubbleBarView: BubbleBarView
private lateinit var stashedHandleView: StashedHandleView
+ private lateinit var bubbleView: BubbleView
private lateinit var barTranslationY: AnimatedFloat
private lateinit var barScaleX: AnimatedFloat
private lateinit var barScaleY: AnimatedFloat
private lateinit var barAlpha: MultiValueAlpha
+ private lateinit var bubbleOffsetY: AnimatedFloat
private lateinit var bubbleAlpha: AnimatedFloat
private lateinit var backgroundAlpha: AnimatedFloat
private lateinit var stashedHandleAlpha: MultiValueAlpha
@@ -105,7 +108,7 @@
taskbarInsetsController,
bubbleBarViewController,
bubbleStashedHandleViewController,
- ImmediateAction()
+ ImmediateAction(),
)
}
@@ -161,11 +164,13 @@
mTransientBubbleStashController.isStashed = false
whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+ val bubbleInitialTranslation = bubbleView.translationY
+
// When stash
getInstrumentation().runOnMainSync {
mTransientBubbleStashController.updateStashedAndExpandedState(
stash = true,
- expand = false
+ expand = false,
)
}
@@ -181,9 +186,13 @@
assertThat(bubbleBarView.alpha).isEqualTo(0f)
assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX())
assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY())
+ assertThat(bubbleBarView.background.alpha).isEqualTo(255)
// Handle view is visible
assertThat(stashedHandleView.translationY).isEqualTo(0)
assertThat(stashedHandleView.alpha).isEqualTo(1)
+ // Bubble view is reset
+ assertThat(bubbleView.translationY).isEqualTo(bubbleInitialTranslation)
+ assertThat(bubbleView.alpha).isEqualTo(1f)
}
@Test
@@ -274,7 +283,7 @@
val height = mTransientBubbleStashController.getTouchableHeight()
// Then bubble bar height is returned
- assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT.toInt())
+ assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT)
}
private fun advanceTimeBy(advanceMs: Long) {
@@ -285,20 +294,26 @@
private fun setUpBubbleBarView() {
getInstrumentation().runOnMainSync {
bubbleBarView = BubbleBarView(context)
- bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
+ bubbleBarView.layoutParams =
+ FrameLayout.LayoutParams(BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT)
+ bubbleView = BubbleView(context)
+ bubbleBarView.addBubble(bubbleView)
+ bubbleBarView.layout(0, 0, BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT)
}
}
private fun setUpStashedHandleView() {
getInstrumentation().runOnMainSync {
stashedHandleView = StashedHandleView(context)
- stashedHandleView.layoutParams = FrameLayout.LayoutParams(0, 0)
+ stashedHandleView.layoutParams =
+ FrameLayout.LayoutParams(HANDLE_VIEW_WIDTH, HANDLE_VIEW_HEIGHT)
}
}
private fun setUpBubbleBarController() {
barTranslationY =
AnimatedFloat(Runnable { bubbleBarView.translationY = barTranslationY.value })
+ bubbleOffsetY = AnimatedFloat { value -> bubbleBarView.setBubbleOffsetY(value) }
barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value }
barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value }
barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
@@ -307,13 +322,16 @@
whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY)
+ whenever(bubbleBarViewController.bubbleOffsetY).thenReturn(bubbleOffsetY)
whenever(bubbleBarViewController.bubbleBarBackgroundScaleX).thenReturn(barScaleX)
whenever(bubbleBarViewController.bubbleBarBackgroundScaleY).thenReturn(barScaleY)
whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha)
whenever(bubbleBarViewController.bubbleBarBubbleAlpha).thenReturn(bubbleAlpha)
whenever(bubbleBarViewController.bubbleBarBackgroundAlpha).thenReturn(backgroundAlpha)
- whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH)
- whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
+ whenever(bubbleBarViewController.bubbleBarCollapsedWidth)
+ .thenReturn(BUBBLE_BAR_WIDTH.toFloat())
+ whenever(bubbleBarViewController.bubbleBarCollapsedHeight)
+ .thenReturn(BUBBLE_BAR_HEIGHT.toFloat())
whenever(bubbleBarViewController.createRevealAnimatorForStashChange(any()))
.thenReturn(AnimatorSet())
}
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 fe67313..33d96a8 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,6 +70,55 @@
assertThat(thumbnailDataFlow2.first()).isNull()
}
+ @Test
+ fun updatesRunningTaskShowScreenshot() = runTest {
+ systemUnderTest.setRunningTaskShowScreenshot(true)
+ systemUnderTest.waitForRunningTaskShowScreenshotToUpdate()
+ }
+
+ @Test
+ fun waitForThumbnailsToUpdate() = runTest {
+ // Given taskRepository with visible 2 tasks containing thumbnailData
+ val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 }
+ val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 }
+ tasksRepository.seedTasks(tasks)
+ tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2))
+ systemUnderTest.updateVisibleTasks(listOf(1, 2))
+
+ val thumbnailDataFlow1 = tasksRepository.getThumbnailById(1)
+ val thumbnailDataFlow2 = tasksRepository.getThumbnailById(2)
+
+ // Then getThumbnailById should initially contains correct thumbnailData
+ assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
+ assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2)
+
+ // When thumbnailData is updated in taskRepository
+ tasksRepository.seedThumbnailData(
+ mapOf(1 to thumbnailData1, 2 to createThumbnailData().apply { snapshotId = 3 })
+ )
+ // setVisibleTasks forces FakeTasksRepository to update the flows returned by
+ // getThumbnailById
+ tasksRepository.setVisibleTasks(listOf(1, 2))
+
+ // Then wait for thumbnailData should complete, and the previous getThumbnailById flow
+ // should return updated values
+ systemUnderTest.waitForThumbnailsToUpdate(
+ mapOf(2 to createThumbnailData().apply { snapshotId = 3 })
+ )
+ assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1)
+ assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3)
+ }
+
+ @Test
+ fun waitForThumbnailsToUpdate_emptyMap() = runTest {
+ systemUnderTest.waitForThumbnailsToUpdate(emptyMap())
+ }
+
+ @Test
+ fun waitForThumbnailsToUpdate_null() = runTest {
+ systemUnderTest.waitForThumbnailsToUpdate(null)
+ }
+
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/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 2e456a7..2858929 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -248,7 +248,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/355042336
public void testOverview() throws IOException {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 23a29f7..800fd4a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import android.util.Log;
@@ -117,7 +118,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/334946529
public void testUserInstalledAppIsShownAboveDivider() throws IOException {
// Ensure that the App is not installed in main user otherwise, it may not be found in
// PS container.
@@ -142,7 +142,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/334946529
public void testPrivateSpaceAppLongPressUninstallMenu() throws IOException {
// Ensure that the App is not installed in main user otherwise, it may not be found in
// PS container.
@@ -166,8 +165,9 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/334946529
+ @ScreenRecordRule.ScreenRecord // b/355466672
public void testPrivateSpaceLockingBehaviour() throws IOException {
+ assumeFalse(mLauncher.isTablet()); // b/367258373
// Scroll to the bottom of All Apps
executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
HomeAllApps homeAllApps = mLauncher.getAllApps();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 3e6436b..113b8a4 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -350,7 +350,6 @@
@Test
@TaskbarModeSwitch
- @ScreenRecord // b/358607191
public void testQuickSwitchToPreviousAppForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
startTestActivity(2);
@@ -578,7 +577,7 @@
public void testExcludeFromRecents() throws Exception {
startExcludeFromRecentsTestActivity();
OverviewTask currentTask = getAndAssertLaunchedApp().switchToOverview().getCurrentTask();
- // TODO(b/326565120): the expected content description shouldn't be null but for now there
+ // TODO(b/342627272): the expected content description shouldn't be null but for now there
// is a bug that causes it to sometimes be for excludeForRecents tasks.
assertTrue("Can't find ExcludeFromRecentsTestActivity after entering Overview from it",
currentTask.containsContentDescription("ExcludeFromRecents")
diff --git a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
deleted file mode 100644
index 47f2a5d..0000000
--- a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="52dp"
- android:height="52dp"
- android:viewportWidth="52"
- android:viewportHeight="52">
- <path
- android:pathData="M15.5,19C14.538,19 13.715,18.65 13.033,17.968C12.35,17.285 12,16.462 12,15.5C12,14.538 12.35,13.715 13.033,13.033C13.715,12.35 14.538,12 15.5,12C16.462,12 17.285,12.35 17.968,13.033C18.65,13.715 19,14.538 19,15.5C19,16.462 18.65,17.285 17.968,17.968C17.285,18.65 16.462,19 15.5,19Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M26,19C25.038,19 24.215,18.65 23.532,17.968C22.85,17.285 22.5,16.462 22.5,15.5C22.5,14.538 22.85,13.715 23.532,13.033C24.215,12.35 25.038,12 26,12C26.962,12 27.785,12.35 28.468,13.033C29.15,13.715 29.5,14.538 29.5,15.5C29.5,16.462 29.15,17.285 28.468,17.968C27.785,18.65 26.962,19 26,19Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M36.5,19C35.537,19 34.715,18.65 34.033,17.968C33.35,17.285 33,16.462 33,15.5C33,14.538 33.35,13.715 34.033,13.033C34.715,12.35 35.537,12 36.5,12C37.463,12 38.285,12.35 38.967,13.033C39.65,13.715 40,14.538 40,15.5C40,16.462 39.65,17.285 38.967,17.968C38.285,18.65 37.463,19 36.5,19Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M15.5,29.5C14.538,29.5 13.715,29.15 13.033,28.468C12.35,27.785 12,26.962 12,26C12,25.038 12.35,24.215 13.033,23.532C13.715,22.85 14.538,22.5 15.5,22.5C16.462,22.5 17.285,22.85 17.968,23.532C18.65,24.215 19,25.038 19,26C19,26.962 18.65,27.785 17.968,28.468C17.285,29.15 16.462,29.5 15.5,29.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M26,29.5C25.038,29.5 24.215,29.15 23.532,28.468C22.85,27.785 22.5,26.962 22.5,26C22.5,25.038 22.85,24.215 23.532,23.532C24.215,22.85 25.038,22.5 26,22.5C26.962,22.5 27.785,22.85 28.468,23.532C29.15,24.215 29.5,25.038 29.5,26C29.5,26.962 29.15,27.785 28.468,28.468C27.785,29.15 26.962,29.5 26,29.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M36.5,29.5C35.537,29.5 34.715,29.15 34.033,28.468C33.35,27.785 33,26.962 33,26C33,25.038 33.35,24.215 34.033,23.532C34.715,22.85 35.537,22.5 36.5,22.5C37.463,22.5 38.285,22.85 38.967,23.532C39.65,24.215 40,25.038 40,26C40,26.962 39.65,27.785 38.967,28.468C38.285,29.15 37.463,29.5 36.5,29.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M15.5,40C14.538,40 13.715,39.65 13.033,38.967C12.35,38.285 12,37.463 12,36.5C12,35.537 12.35,34.715 13.033,34.033C13.715,33.35 14.538,33 15.5,33C16.462,33 17.285,33.35 17.968,34.033C18.65,34.715 19,35.537 19,36.5C19,37.463 18.65,38.285 17.968,38.967C17.285,39.65 16.462,40 15.5,40Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M26,40C25.038,40 24.215,39.65 23.532,38.967C22.85,38.285 22.5,37.463 22.5,36.5C22.5,35.537 22.85,34.715 23.532,34.033C24.215,33.35 25.038,33 26,33C26.962,33 27.785,33.35 28.468,34.033C29.15,34.715 29.5,35.537 29.5,36.5C29.5,37.463 29.15,38.285 28.468,38.967C27.785,39.65 26.962,40 26,40Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M36.5,40C35.537,40 34.715,39.65 34.033,38.967C33.35,38.285 33,37.463 33,36.5C33,35.537 33.35,34.715 34.033,34.033C34.715,33.35 35.537,33 36.5,33C37.463,33 38.285,33.35 38.967,34.033C39.65,34.715 40,35.537 40,36.5C40,37.463 39.65,38.285 38.967,38.967C38.285,39.65 37.463,40 36.5,40Z"
- android:fillColor="#40484B"/>
-</vector>
diff --git a/res/drawable/ic_taskbar_all_apps_button.xml b/res/drawable/ic_taskbar_all_apps_button.xml
deleted file mode 100644
index 82fbbea..0000000
--- a/res/drawable/ic_taskbar_all_apps_button.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="44dp"
- android:height="44dp"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M13,16C12.175,16 11.47,15.7 10.885,15.115C10.3,14.53 10,13.825 10,13C10,12.175 10.3,11.47 10.885,10.885C11.47,10.3 12.175,10 13,10C13.825,10 14.53,10.3 15.115,10.885C15.7,11.47 16,12.175 16,13C16,13.825 15.7,14.53 15.115,15.115C14.53,15.7 13.825,16 13,16Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M22,16C21.175,16 20.47,15.7 19.885,15.115C19.3,14.53 19,13.825 19,13C19,12.175 19.3,11.47 19.885,10.885C20.47,10.3 21.175,10 22,10C22.825,10 23.53,10.3 24.115,10.885C24.7,11.47 25,12.175 25,13C25,13.825 24.7,14.53 24.115,15.115C23.53,15.7 22.825,16 22,16Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M31,16C30.175,16 29.47,15.7 28.885,15.115C28.3,14.53 28,13.825 28,13C28,12.175 28.3,11.47 28.885,10.885C29.47,10.3 30.175,10 31,10C31.825,10 32.53,10.3 33.115,10.885C33.7,11.47 34,12.175 34,13C34,13.825 33.7,14.53 33.115,15.115C32.53,15.7 31.825,16 31,16Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M13,25C12.175,25 11.47,24.7 10.885,24.115C10.3,23.53 10,22.825 10,22C10,21.175 10.3,20.47 10.885,19.885C11.47,19.3 12.175,19 13,19C13.825,19 14.53,19.3 15.115,19.885C15.7,20.47 16,21.175 16,22C16,22.825 15.7,23.53 15.115,24.115C14.53,24.7 13.825,25 13,25Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M22,25C21.175,25 20.47,24.7 19.885,24.115C19.3,23.53 19,22.825 19,22C19,21.175 19.3,20.47 19.885,19.885C20.47,19.3 21.175,19 22,19C22.825,19 23.53,19.3 24.115,19.885C24.7,20.47 25,21.175 25,22C25,22.825 24.7,23.53 24.115,24.115C23.53,24.7 22.825,25 22,25Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M31,25C30.175,25 29.47,24.7 28.885,24.115C28.3,23.53 28,22.825 28,22C28,21.175 28.3,20.47 28.885,19.885C29.47,19.3 30.175,19 31,19C31.825,19 32.53,19.3 33.115,19.885C33.7,20.47 34,21.175 34,22C34,22.825 33.7,23.53 33.115,24.115C32.53,24.7 31.825,25 31,25Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M13,34C12.175,34 11.47,33.7 10.885,33.115C10.3,32.53 10,31.825 10,31C10,30.175 10.3,29.47 10.885,28.885C11.47,28.3 12.175,28 13,28C13.825,28 14.53,28.3 15.115,28.885C15.7,29.47 16,30.175 16,31C16,31.825 15.7,32.53 15.115,33.115C14.53,33.7 13.825,34 13,34Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M22,34C21.175,34 20.47,33.7 19.885,33.115C19.3,32.53 19,31.825 19,31C19,30.175 19.3,29.47 19.885,28.885C20.47,28.3 21.175,28 22,28C22.825,28 23.53,28.3 24.115,28.885C24.7,29.47 25,30.175 25,31C25,31.825 24.7,32.53 24.115,33.115C23.53,33.7 22.825,34 22,34Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M31,34C30.175,34 29.47,33.7 28.885,33.115C28.3,32.53 28,31.825 28,31C28,30.175 28.3,29.47 28.885,28.885C29.47,28.3 30.175,28 31,28C31.825,28 32.53,28.3 33.115,28.885C33.7,29.47 34,30.175 34,31C34,31.825 33.7,32.53 33.115,33.115C32.53,33.7 31.825,34 31,34Z"
- android:fillColor="#40484B"/>
-</vector>
diff --git a/res/drawable/ic_transient_taskbar_all_apps_button.xml b/res/drawable/ic_transient_taskbar_all_apps_button.xml
deleted file mode 100644
index 6e740ae..0000000
--- a/res/drawable/ic_transient_taskbar_all_apps_button.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="48"
- android:viewportHeight="48">
- <path
- android:pathData="M13.5,17C12.538,17 11.715,16.65 11.033,15.967C10.35,15.285 10,14.462 10,13.5C10,12.538 10.35,11.715 11.033,11.033C11.715,10.35 12.538,10 13.5,10C14.462,10 15.285,10.35 15.967,11.033C16.65,11.715 17,12.538 17,13.5C17,14.462 16.65,15.285 15.967,15.967C15.285,16.65 14.462,17 13.5,17Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M24,17C23.038,17 22.215,16.65 21.532,15.967C20.85,15.285 20.5,14.462 20.5,13.5C20.5,12.538 20.85,11.715 21.532,11.033C22.215,10.35 23.038,10 24,10C24.962,10 25.785,10.35 26.468,11.033C27.15,11.715 27.5,12.538 27.5,13.5C27.5,14.462 27.15,15.285 26.468,15.967C25.785,16.65 24.962,17 24,17Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M34.5,17C33.537,17 32.715,16.65 32.033,15.967C31.35,15.285 31,14.462 31,13.5C31,12.538 31.35,11.715 32.033,11.033C32.715,10.35 33.537,10 34.5,10C35.463,10 36.285,10.35 36.967,11.033C37.65,11.715 38,12.538 38,13.5C38,14.462 37.65,15.285 36.967,15.967C36.285,16.65 35.463,17 34.5,17Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M13.5,27.5C12.538,27.5 11.715,27.15 11.033,26.468C10.35,25.785 10,24.962 10,24C10,23.038 10.35,22.215 11.033,21.532C11.715,20.85 12.538,20.5 13.5,20.5C14.462,20.5 15.285,20.85 15.967,21.532C16.65,22.215 17,23.038 17,24C17,24.962 16.65,25.785 15.967,26.468C15.285,27.15 14.462,27.5 13.5,27.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M24,27.5C23.038,27.5 22.215,27.15 21.532,26.468C20.85,25.785 20.5,24.962 20.5,24C20.5,23.038 20.85,22.215 21.532,21.532C22.215,20.85 23.038,20.5 24,20.5C24.962,20.5 25.785,20.85 26.468,21.532C27.15,22.215 27.5,23.038 27.5,24C27.5,24.962 27.15,25.785 26.468,26.468C25.785,27.15 24.962,27.5 24,27.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M34.5,27.5C33.537,27.5 32.715,27.15 32.033,26.468C31.35,25.785 31,24.962 31,24C31,23.038 31.35,22.215 32.033,21.532C32.715,20.85 33.537,20.5 34.5,20.5C35.463,20.5 36.285,20.85 36.967,21.532C37.65,22.215 38,23.038 38,24C38,24.962 37.65,25.785 36.967,26.468C36.285,27.15 35.463,27.5 34.5,27.5Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M13.5,38C12.538,38 11.715,37.65 11.033,36.967C10.35,36.285 10,35.463 10,34.5C10,33.537 10.35,32.715 11.033,32.033C11.715,31.35 12.538,31 13.5,31C14.462,31 15.285,31.35 15.967,32.033C16.65,32.715 17,33.537 17,34.5C17,35.463 16.65,36.285 15.967,36.967C15.285,37.65 14.462,38 13.5,38Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M24,38C23.038,38 22.215,37.65 21.532,36.967C20.85,36.285 20.5,35.463 20.5,34.5C20.5,33.537 20.85,32.715 21.532,32.033C22.215,31.35 23.038,31 24,31C24.962,31 25.785,31.35 26.468,32.033C27.15,32.715 27.5,33.537 27.5,34.5C27.5,35.463 27.15,36.285 26.468,36.967C25.785,37.65 24.962,38 24,38Z"
- android:fillColor="#40484B"/>
- <path
- android:pathData="M34.5,38C33.537,38 32.715,37.65 32.033,36.967C31.35,36.285 31,35.463 31,34.5C31,33.537 31.35,32.715 32.033,32.033C32.715,31.35 33.537,31 34.5,31C35.463,31 36.285,31.35 36.967,32.033C37.65,32.715 38,33.537 38,34.5C38,35.463 37.65,36.285 36.967,36.967C36.285,37.65 35.463,38 34.5,38Z"
- android:fillColor="#40484B"/>
-</vector>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2a6611f..e2be4ff 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -31,7 +31,7 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delt skjerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Bruksinnstillinger for %1$s"</string>
- <string name="save_app_pair" msgid="5647523853662686243">"Lagre apptilkoblingen"</string>
+ <string name="save_app_pair" msgid="5647523853662686243">"Lagre app-paret"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Åpne enheten for å bruke denne apptilkoblingen"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 507ce9a..701e64a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -67,7 +67,6 @@
<string name="main_process_initializer_class" translatable="false"></string>
<string name="app_launch_tracker_class" translatable="false"></string>
<string name="test_information_handler_class" translatable="false"></string>
- <string name="launcher_activity_logic_class" translatable="false"></string>
<string name="model_delegate_class" translatable="false"></string>
<string name="window_manager_proxy_class" translatable="false"></string>
<string name="secondary_display_predictions_class" translatable="false"></string>
diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt
index e022159..f1029b1 100644
--- a/src/com/android/launcher3/DropTargetHandler.kt
+++ b/src/com/android/launcher3/DropTargetHandler.kt
@@ -35,8 +35,7 @@
target?.let {
deferred.mPackageName = it.packageName
mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() }
- }
- ?: deferred.sendFailure()
+ } ?: deferred.sendFailure()
}
}
}
@@ -47,19 +46,10 @@
mLauncher.appWidgetHolder.startConfigActivity(
mLauncher,
widgetId,
- ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET
+ ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET,
)
}
- fun dismissPrediction(
- announcement: CharSequence,
- onActionClicked: Runnable,
- onDismiss: Runnable?
- ) {
- mLauncher.dragLayer.announceForAccessibility(announcement)
- Snackbar.show(mLauncher, R.string.item_removed, R.string.undo, onDismiss, onActionClicked)
- }
-
fun getViewUnderDrag(info: ItemInfo): View? {
return if (
info is LauncherAppWidgetInfo &&
@@ -95,7 +85,7 @@
R.string.item_removed,
R.string.undo,
mLauncher.modelWriter::commitDelete,
- onUndoClicked
+ onUndoClicked,
)
}
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 6622e11..17084bb 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -60,6 +60,7 @@
mScrollbar = scrollbar;
mScrollbar.setRecyclerView(this);
mScrollbar.setFastScrollerLocation(location);
+ scrollToTop();
onUpdateScrollbar(0);
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 0d4ebe0..024dde4 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -33,15 +33,34 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import androidx.annotation.IntDef;
+
import com.android.launcher3.util.HorizontalInsettableView;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiTranslateDelegate;
+import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.views.ActivityContext;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* View class that represents the bottom row of the home screen.
*/
public class Hotseat extends CellLayout implements Insettable {
+ public static final int ALPHA_CHANNEL_TASKBAR_ALIGNMENT = 0;
+ public static final int ALPHA_CHANNEL_PREVIEW_RENDERER = 1;
+ public static final int ALPHA_CHANNEL_TASKBAR_STASH = 2;
+ public static final int ALPHA_CHANNEL_CHANNELS_COUNT = 3;
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @IntDef({ALPHA_CHANNEL_TASKBAR_ALIGNMENT, ALPHA_CHANNEL_PREVIEW_RENDERER,
+ ALPHA_CHANNEL_TASKBAR_STASH})
+ public @interface HotseatQsbAlphaId {
+ }
+
// Ratio of empty space, qsb should take up to appear visually centered.
public static final float QSB_CENTER_FACTOR = .325f;
private static final int BUBBLE_BAR_ADJUSTMENT_ANIMATION_DURATION_MS = 250;
@@ -50,6 +69,8 @@
private boolean mHasVerticalHotseat;
private Workspace<?> mWorkspace;
private boolean mSendTouchToWorkspace;
+ private final MultiValueAlpha mIconsAlphaChannels;
+ private final MultiValueAlpha mQsbAlphaChannels;
private final View mQsb;
@@ -63,9 +84,11 @@
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
addView(mQsb);
+ mIconsAlphaChannels = new MultiValueAlpha(getShortcutsAndWidgets(),
+ ALPHA_CHANNEL_CHANNELS_COUNT);
+ mQsbAlphaChannels = new MultiValueAlpha(mQsb, ALPHA_CHANNEL_CHANNELS_COUNT);
}
/**
@@ -270,21 +293,27 @@
}
/**
- * Sets the alpha value of just our ShortcutAndWidgetContainer.
+ * Sets the alpha value of the specified alpha channel of just our ShortcutAndWidgetContainer.
*/
- public void setIconsAlpha(float alpha) {
- getShortcutsAndWidgets().setAlpha(alpha);
+ public void setIconsAlpha(float alpha, @HotseatQsbAlphaId int channelId) {
+ getIconsAlpha(channelId).setValue(alpha);
}
/**
* Sets the alpha value of just our QSB.
*/
- public void setQsbAlpha(float alpha) {
- mQsb.setAlpha(alpha);
+ public void setQsbAlpha(float alpha, @HotseatQsbAlphaId int channelId) {
+ getQsbAlpha(channelId).setValue(alpha);
}
- public float getIconsAlpha() {
- return getShortcutsAndWidgets().getAlpha();
+ /** Returns the alpha channel for ShortcutAndWidgetContainer */
+ public MultiProperty getIconsAlpha(@HotseatQsbAlphaId int channelId) {
+ return mIconsAlphaChannels.get(channelId);
+ }
+
+ /** Returns the alpha channel for Qsb */
+ public MultiProperty getQsbAlpha(@HotseatQsbAlphaId int channelId) {
+ return mQsbAlphaChannels.get(channelId);
}
/**
@@ -294,4 +323,24 @@
return mQsb;
}
+ /** Dumps the Hotseat internal state */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "Hotseat:");
+ mIconsAlphaChannels.dump(
+ prefix + "\t",
+ writer,
+ "mIconsAlphaChannels",
+ "ALPHA_CHANNEL_TASKBAR_ALIGNMENT",
+ "ALPHA_CHANNEL_PREVIEW_RENDERER",
+ "ALPHA_CHANNEL_TASKBAR_STASH");
+ mQsbAlphaChannels.dump(
+ prefix + "\t",
+ writer,
+ "mQsbAlphaChannels",
+ "ALPHA_CHANNEL_TASKBAR_ALIGNMENT",
+ "ALPHA_CHANNEL_PREVIEW_RENDERER",
+ "ALPHA_CHANNEL_TASKBAR_STASH"
+ );
+ }
+
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 365e3d4..0bc192d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -76,7 +76,6 @@
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
@@ -1251,9 +1250,7 @@
* Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
*/
protected Optional<EventEnum> getAllAppsEntryEvent() {
- return Optional.of(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
- ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
- : LAUNCHER_ALLAPPS_ENTRY);
+ return Optional.of(LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH);
}
@Override
@@ -2678,6 +2675,7 @@
}
writer.println(prefix + " Hotseat");
+ mHotseat.dump(prefix, writer);
ViewGroup layout = mHotseat.getShortcutsAndWidgets();
for (int j = 0; j < layout.getChildCount(); j++) {
Object tag = layout.getChildAt(j).getTag();
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 8969b60..490186a 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -30,7 +30,7 @@
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
- mAppComponent = DaggerLauncherAppComponent.builder().build();
+ mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
}
public LauncherBaseAppComponent getAppComponent() {
diff --git a/src/com/android/launcher3/MotionEventsUtils.java b/src/com/android/launcher3/MotionEventsUtils.java
index 3228ec6..fb244b0 100644
--- a/src/com/android/launcher3/MotionEventsUtils.java
+++ b/src/com/android/launcher3/MotionEventsUtils.java
@@ -18,8 +18,6 @@
import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
-
import android.annotation.TargetApi;
import android.os.Build;
import android.view.MotionEvent;
@@ -35,14 +33,12 @@
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static boolean isTrackpadScroll(MotionEvent event) {
- return ENABLE_TRACKPAD_GESTURE.get()
- && event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE;
+ return event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE;
}
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static boolean isTrackpadMultiFingerSwipe(MotionEvent event) {
- return ENABLE_TRACKPAD_GESTURE.get()
- && event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
+ return event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE;
}
public static boolean isTrackpadThreeFingerSwipe(MotionEvent event) {
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 0a4fb73..8d1e61f 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -7,7 +7,6 @@
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.INVALID;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_UNINSTALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_CANCELLED;
@@ -36,7 +35,6 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.InstanceId;
@@ -242,8 +240,7 @@
@Override
public void completeDrop(final DragObject d) {
- ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo,
- d.logInstanceId);
+ ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo);
mDropTargetHandler.onSecondaryTargetCompleteDrop(target, d);
}
@@ -275,7 +272,7 @@
* Performs the drop action and returns the target component for the dragObject or null if
* the action was not performed.
*/
- protected ComponentName performDropAction(View view, ItemInfo info, InstanceId instanceId) {
+ protected ComponentName performDropAction(View view, ItemInfo info) {
if (mCurrentAccessibilityAction == RECONFIGURE) {
int widgetId = getReconfigurableWidgetId(view);
if (widgetId != INVALID_APPWIDGET_ID) {
@@ -283,21 +280,6 @@
}
return null;
}
- if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
- if (FeatureFlags.ENABLE_DISMISS_PREDICTION_UNDO.get()) {
- CharSequence announcement = getContext().getString(R.string.item_removed);
- mDropTargetHandler
- .dismissPrediction(announcement, () -> {
- }, () -> {
- mStatsLogManager.logger()
- .withInstanceId(instanceId)
- .withItemInfo(info)
- .log(LAUNCHER_DISMISS_PREDICTION_UNDO);
- });
- }
- return null;
- }
-
return performUninstall(getContext(), getUninstallTarget(getContext(), info), info);
}
@@ -332,9 +314,8 @@
@Override
public void onAccessibilityDrop(View view, ItemInfo item) {
- InstanceId instanceId = new InstanceIdSequence().newInstanceId();
- doLog(instanceId, item);
- performDropAction(view, item, instanceId);
+ doLog(new InstanceIdSequence().newInstanceId(), item);
+ performDropAction(view, item);
}
/**
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index cc4724c..1094768 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -22,8 +22,6 @@
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
-import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
@@ -679,18 +677,13 @@
@NonNull AllAppsRecyclerView mainRecyclerView,
@Nullable AllAppsRecyclerView workRecyclerView,
@NonNull AllAppsRecyclerViewPool recycledViewPool) {
- if (!ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
- return;
- }
final boolean hasWorkProfile = workRecyclerView != null;
recycledViewPool.setHasWorkProfile(hasWorkProfile);
mainRecyclerView.setRecycledViewPool(recycledViewPool);
if (workRecyclerView != null) {
workRecyclerView.setRecycledViewPool(recycledViewPool);
}
- if (ALL_APPS_GONE_VISIBILITY.get()) {
- mainRecyclerView.updatePoolSize(hasWorkProfile);
- }
+ mainRecyclerView.updatePoolSize(hasWorkProfile);
}
private void replaceAppsRVContainer(boolean showTabs) {
@@ -735,9 +728,7 @@
removeCustomRules(rvContainer);
removeCustomRules(getSearchRecyclerView());
- if (!isSearchSupported()) {
- layoutWithoutSearchContainer(rvContainer, showTabs);
- } else if (isSearchBarFloating()) {
+ if (isSearchBarFloating()) {
alignParentTop(rvContainer, showTabs);
alignParentTop(getSearchRecyclerView(), /* tabs= */ false);
} else {
@@ -768,9 +759,7 @@
});
removeCustomRules(mHeader);
- if (!isSearchSupported()) {
- layoutWithoutSearchContainer(mHeader, false /* includeTabsMargin */);
- } else if (isSearchBarFloating()) {
+ if (isSearchBarFloating()) {
alignParentTop(mHeader, false /* includeTabsMargin */);
} else {
layoutBelowSearchContainer(mHeader, false /* includeTabsMargin */);
@@ -925,23 +914,6 @@
mMainAdapterProvider);
}
- // TODO(b/216683257): Remove when Taskbar All Apps supports search.
- protected boolean isSearchSupported() {
- return true;
- }
-
- private void layoutWithoutSearchContainer(View v, boolean includeTabsMargin) {
- if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
- return;
- }
-
- RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams();
- layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- layoutParams.topMargin = getContext().getResources().getDimensionPixelSize(includeTabsMargin
- ? R.dimen.all_apps_header_pill_height
- : R.dimen.all_apps_header_top_margin);
- }
-
public boolean isInAllApps() {
// TODO: Make this abstract
return true;
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 911612f..77a0fe3 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.allapps;
+import static android.view.HapticFeedbackConstants.CLOCK_TICK;
+
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
@@ -71,6 +73,7 @@
@Override
protected int getVerticalSnapPreference() {
+ mRv.performHapticFeedback(CLOCK_TICK);
return SNAP_TO_ANY;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index ae45a35..4e1e950 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -18,8 +18,6 @@
import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
-import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import static com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_PERSONAL_SCROLLED_DOWN;
@@ -124,13 +122,11 @@
// all apps.
int maxPoolSizeForAppIcons = grid.getMaxAllAppsRowCount()
* grid.numShownAllAppsColumns;
- if (ALL_APPS_GONE_VISIBILITY.get() && ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
- // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to
- // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows +
- // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly.
- maxPoolSizeForAppIcons +=
- PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT;
- }
+ // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to
+ // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows +
+ // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly.
+ maxPoolSizeForAppIcons +=
+ PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT;
if (hasWorkProfile) {
maxPoolSizeForAppIcons *= 2;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index a4f130a..29b9e77 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
@@ -109,7 +108,7 @@
mPackageUserKeytoUidMap = map;
// Preinflate all apps RV when apps has changed, which can happen after unlocking screen,
// rotating screen, or downloading/upgrading apps.
- if (shouldPreinflate && ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
+ if (shouldPreinflate) {
mAllAppsRecyclerViewPool.preInflateAllAppsViewHolders(mContext);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 742648e..c6852e0 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -54,7 +54,6 @@
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
@@ -413,8 +412,7 @@
mAppsView = appsView;
mAppsView.setScrimView(scrimView);
- mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT,
- FeatureFlags.ALL_APPS_GONE_VISIBILITY.get() ? View.GONE : View.INVISIBLE);
+ mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT, View.GONE);
mAppsViewAlpha.setUpdateVisibility(true);
mAppsViewTranslationY = new MultiPropertyFactory<>(
mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum);
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index a2bd5dd..ac06ab4 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -34,7 +34,6 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.views.ActivityContext;
import com.android.systemui.plugins.AllAppsRow;
@@ -220,15 +219,12 @@
@Override
public View getFocusedChild() {
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- for (FloatingHeaderRow row : mAllRows) {
- if (row.hasVisibleContent() && row.isVisible()) {
- return row.getFocusedChild();
- }
+ for (FloatingHeaderRow row : mAllRows) {
+ if (row.hasVisibleContent() && row.isVisible()) {
+ return row.getFocusedChild();
}
- return null;
}
- return super.getFocusedChild();
+ return null;
}
void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, SearchRecyclerView searchRV,
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index ec45415..de3bb9e 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -22,8 +22,6 @@
import android.text.style.SuggestionSpan;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnFocusChangeListener;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -31,7 +29,6 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.views.ActivityContext;
@@ -40,8 +37,7 @@
* An interface to a search box that AllApps can command.
*/
public class AllAppsSearchBarController
- implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
- OnFocusChangeListener {
+ implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener {
private static final String TAG = "AllAppsSearchBarController";
protected ActivityContext mLauncher;
@@ -69,7 +65,6 @@
mInput.addTextChangedListener(this);
mInput.setOnEditorActionListener(this);
mInput.setOnBackKeyListener(this);
- mInput.addOnFocusChangeListener(this);
mSearchAlgorithm = searchAlgorithm;
}
@@ -142,13 +137,6 @@
return false;
}
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- mInput.hideKeyboard();
- }
- }
-
/**
* Resets the search bar state.
*/
@@ -157,7 +145,6 @@
mInput.reset();
mInput.clearFocus();
mQuery = null;
- mInput.removeOnFocusChangeListener(this);
}
/**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 092b524..8fe1b34 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -63,12 +63,6 @@
* <p>
*/
// TODO(Block 3): Clean up flags
- public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
- "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
- "Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
- public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
- "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
-
public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
"ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
"load the current workspace screen visible to the user before the rest rather than "
@@ -79,16 +73,7 @@
"changes the timing of the loading and binding of delegate items during "
+ "data preparation for loading the home screen");
- // TODO(Block 4): Cleanup flags
- public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
- 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
- "Enable option to show keyboard when going to all-apps");
-
// TODO(Block 6): Clean up flags
- public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
- "ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", ENABLED,
- "Enables Search box in Taskbar All Apps.");
-
public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140,
"SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
"Enable dragging and dropping to pin apps within secondary display");
@@ -150,28 +135,11 @@
public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
"PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps");
- public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907,
- "ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps");
-
- public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930,
- "ENABLE_HIDE_HEADER", ENABLED, "Hide header on keyboard before typing in all apps");
-
// Aconfig migration complete for ENABLE_EXPANDING_PAUSE_WORK_BUTTON.
public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getDebugFlag(270390779,
"ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED,
"Expand and collapse pause work button while scrolling");
- // Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS.
- public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
- "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
-
- public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
- "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
-
- public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
- "FOLDER_NAME_MAJORITY_RANKING", ENABLED,
- "Suggests folder names based on majority based ranking.");
-
public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706,
"INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED,
"Inject fallback app corpus result when AiAi fails to return it.");
@@ -196,24 +164,7 @@
return ENABLE_APP_PAIRS.get() || com.android.wm.shell.Flags.enableAppPairs();
}
- // TODO(Block 19): Clean up flags
- public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(270395177,
- "SCROLL_TOP_TO_RESET", ENABLED,
- "Bring up IME and focus on input when scroll to top if 'Always show keyboard'"
- + " is enabled or in prefix state");
-
- public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269,
- "ENABLE_SEARCH_UNINSTALLED_APPS", ENABLED, "Search uninstalled app results.");
-
// TODO(Block 20): Clean up flags
- public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426,
- "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED,
- "Enables home animation to icon when user swipes back.");
-
- public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473,
- "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
- "Enables taskbar thresholds that scale based on screen size.");
-
// Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER.
public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414,
"ENABLE_HOME_TRANSITION_LISTENER", DISABLED,
@@ -232,18 +183,7 @@
"ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
"Enable widget transition animation when resizing the widgets");
- public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
- "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
- "Enables starting the unfold animation preemptively when unfolding, without"
- + "waiting for SystemUI and then merging the SystemUI progress whenever we "
- + "start receiving the events");
-
// TODO(Block 25): Clean up flags
- public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
- "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
- "Enable the redesigned gesture navigation tutorial");
-
- // TODO(Block 26): Clean up flags
public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384,
"ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED,
"Enable background widget updates listening for widget holder");
@@ -268,10 +208,6 @@
"SEPARATE_RECENTS_ACTIVITY", DISABLED,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
- public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258,
- "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
- "Enforce rounded corners on all App Widgets");
-
public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
"USE_LOCAL_ICON_OVERRIDES", ENABLED,
"Use inbuilt monochrome icons if app doesn't provide one");
@@ -285,20 +221,15 @@
com.android.wm.shell.Flags.enableSplitContextual();
}
- public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
- "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
-
// TODO(Block 29): Clean up flags
+ // Aconfig migration complete for ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.
public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
"ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED,
"Enables displaying the all apps button in the hotseat.");
- public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
- "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching");
-
- public static final BooleanFlag ENABLE_KEYBOARD_TASKBAR_TOGGLE = getDebugFlag(281726846,
- "ENABLE_KEYBOARD_TASKBAR_TOGGLE", ENABLED,
- "Enables keyboard taskbar stash toggling");
+ public static boolean enableAllAppsButtonInHotseat() {
+ return ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get() || Flags.enableAllAppsButtonInHotseat();
+ }
// TODO(Block 30): Clean up flags
public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
@@ -317,14 +248,6 @@
return ENABLE_RESPONSIVE_WORKSPACE.get() || Flags.enableResponsiveWorkspace();
}
- // TODO(Block 33): Clean up flags
- public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
- "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
- "Enables preinflating all apps icons to avoid scrolling jank.");
- public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
- "ALL_APPS_GONE_VISIBILITY", ENABLED,
- "Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
-
public static BooleanFlag getDebugFlag(
int bugId, String key, BooleanFlag flagState, String description) {
return flagState;
diff --git a/src/com/android/launcher3/dagger/ActivityContextScope.java b/src/com/android/launcher3/dagger/ActivityContextScope.java
new file mode 100644
index 0000000..887f15c
--- /dev/null
+++ b/src/com/android/launcher3/dagger/ActivityContextScope.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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singletons associated with Launcher activity context.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Scope
+public @interface ActivityContextScope {
+}
diff --git a/src/com/android/launcher3/dagger/ApplicationContext.java b/src/com/android/launcher3/dagger/ApplicationContext.java
new file mode 100644
index 0000000..9a5b08b
--- /dev/null
+++ b/src/com/android/launcher3/dagger/ApplicationContext.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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/**
+ * Qualifier for Launcher application context.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface ApplicationContext {
+}
diff --git a/src/com/android/launcher3/dagger/LauncherAppSingleton.java b/src/com/android/launcher3/dagger/LauncherAppSingleton.java
new file mode 100644
index 0000000..92c00b6
--- /dev/null
+++ b/src/com/android/launcher3/dagger/LauncherAppSingleton.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;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the LauncherAppComponent.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Scope
+public @interface LauncherAppSingleton {
+}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 3488c95..1a59d82 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -16,6 +16,10 @@
package com.android.launcher3.dagger;
+import android.content.Context;
+
+import dagger.BindsInstance;
+
/**
* Launcher base component for Dagger injection.
*
@@ -27,6 +31,7 @@
public interface LauncherBaseAppComponent {
/** Builder for LauncherBaseAppComponent. */
interface Builder {
+ @BindsInstance Builder appContext(@ApplicationContext Context context);
LauncherBaseAppComponent build();
}
}
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 374c07b..531cdfd 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -16,11 +16,13 @@
package com.android.launcher3.graphics;
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.Themes.isThemedIconEnabled;
import android.content.ContentProvider;
import android.content.ContentValues;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
@@ -39,8 +41,15 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.GridOption;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.Preconditions;
+import com.android.systemui.shared.Flags;
+
+import java.util.concurrent.ExecutionException;
/**
* Exposes various launcher grid options and allows the caller to change them.
@@ -144,14 +153,20 @@
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- switch (uri.getPath()) {
+ String path = uri.getPath();
+ Context context = getContext();
+ if (path == null || context == null) {
+ return 0;
+ }
+ switch (path) {
case KEY_DEFAULT_GRID: {
String gridName = values.getAsString(KEY_NAME);
- InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
// Verify that this is a valid grid option
GridOption match = null;
- for (GridOption option : idp.parseAllGridOptions(getContext())) {
- if (option.name.equals(gridName)) {
+ for (GridOption option : idp.parseAllGridOptions(context)) {
+ String name = option.name;
+ if (name != null && name.equals(gridName)) {
match = option;
break;
}
@@ -160,15 +175,23 @@
return 0;
}
- idp.setCurrentGrid(getContext(), gridName);
- getContext().getContentResolver().notifyChange(uri, null);
+ idp.setCurrentGrid(context, gridName);
+ if (Flags.newCustomizationPickerUi()) {
+ try {
+ // Wait for device profile to be fully reloaded and applied to the launcher
+ loadModelSync(context);
+ } catch (ExecutionException | InterruptedException e) {
+ Log.e(TAG, "Fail to load model", e);
+ }
+ }
+ context.getContentResolver().notifyChange(uri, null);
return 1;
}
case ICON_THEMED:
case SET_ICON_THEMED: {
- LauncherPrefs.get(getContext())
+ LauncherPrefs.get(context)
.put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
- getContext().getContentResolver().notifyChange(uri, null);
+ context.getContentResolver().notifyChange(uri, null);
return 1;
}
default:
@@ -176,6 +199,23 @@
}
}
+ /**
+ * Loads the model in memory synchronously
+ */
+ private void loadModelSync(Context context) throws ExecutionException, InterruptedException {
+ Preconditions.assertNonUiThread();
+ BgDataModel.Callbacks emptyCallbacks = new BgDataModel.Callbacks() { };
+ LauncherModel launcherModel = LauncherAppState.getInstance(context).getModel();
+ MAIN_EXECUTOR.submit(
+ () -> launcherModel.addCallbacksAndLoad(emptyCallbacks)
+ ).get();
+
+ Executors.MODEL_EXECUTOR.submit(() -> { }).get();
+ MAIN_EXECUTOR.submit(
+ () -> launcherModel.removeCallbacks(emptyCallbacks)
+ ).get();
+ }
+
@Override
public Bundle call(String method, String arg, Bundle extras) {
if (getContext().checkPermission("android.permission.BIND_WALLPAPER",
@@ -227,7 +267,7 @@
}
observer.destroyed = true;
observer.renderer.getHostToken().unlinkToDeath(observer, 0);
- Executors.MAIN_EXECUTOR.execute(observer.renderer::destroy);
+ MAIN_EXECUTOR.execute(observer.renderer::destroy);
PreviewLifecycleObserver cached = mActivePreviews.get(observer.getIdentifier());
if (cached == observer) {
mActivePreviews.remove(observer.getIdentifier());
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 2408955..4af9e2f 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE;
import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
+import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_PREVIEW_RENDERER;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
@@ -320,12 +321,12 @@
mUiHandler.post(() -> {
if (mDp.isTaskbarPresent) {
// hotseat icons on bottom
- mHotseat.setIconsAlpha(hide ? 0 : 1);
+ mHotseat.setIconsAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER);
if (mDp.isQsbInline) {
- mHotseat.setQsbAlpha(hide ? 0 : 1);
+ mHotseat.setQsbAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER);
}
} else {
- mHotseat.setQsbAlpha(hide ? 0 : 1);
+ mHotseat.setQsbAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER);
}
});
}
diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java
deleted file mode 100644
index 30575fc..0000000
--- a/src/com/android/launcher3/icons/ComponentWithLabel.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.icons;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.icons.cache.CachingLogic;
-
-public interface ComponentWithLabel {
-
- ComponentName getComponent();
-
- UserHandle getUser();
-
- CharSequence getLabel(PackageManager pm);
-
-
- class ComponentCachingLogic<T extends ComponentWithLabel> implements CachingLogic<T> {
-
- private final PackageManager mPackageManager;
- private final boolean mAddToMemCache;
-
- public ComponentCachingLogic(Context context, boolean addToMemCache) {
- mPackageManager = context.getPackageManager();
- mAddToMemCache = addToMemCache;
- }
-
- @Override
- @NonNull
- public ComponentName getComponent(@NonNull T object) {
- return object.getComponent();
- }
-
- @NonNull
- @Override
- public UserHandle getUser(@NonNull T object) {
- return object.getUser();
- }
-
- @NonNull
- @Override
- public CharSequence getLabel(@NonNull T object) {
- return object.getLabel(mPackageManager);
- }
-
- @NonNull
- @Override
- public BitmapInfo loadIcon(@NonNull Context context, @NonNull T object) {
- return BitmapInfo.LOW_RES_INFO;
- }
-
- @Override
- public boolean addToMemCache() {
- return mAddToMemCache;
- }
- }
-}
diff --git a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java
deleted file mode 100644
index 0a52dd7..0000000
--- a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.icons;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.icons.BaseIconFactory.IconOptions;
-
-/**
- * Extension of ComponentWithLabel to also support loading icons
- */
-public interface ComponentWithLabelAndIcon extends ComponentWithLabel {
-
- /**
- * Provide an icon for this object
- */
- Drawable getFullResIcon(IconCache cache);
-
- class ComponentWithIconCachingLogic extends ComponentCachingLogic<ComponentWithLabelAndIcon> {
-
- public ComponentWithIconCachingLogic(Context context, boolean addToMemCache) {
- super(context, addToMemCache);
- }
-
- @NonNull
- @Override
- public BitmapInfo loadIcon(@NonNull Context context,
- @NonNull ComponentWithLabelAndIcon object) {
- Drawable d = object.getFullResIcon(LauncherAppState.getInstance(context)
- .getIconCache());
- if (d == null) {
- return super.loadIcon(context, object);
- }
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
- return li.createBadgedIconBitmap(d, new IconOptions().setUser(object.getUser()));
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 44e448e..587dc27 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -54,9 +54,10 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
-import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
import com.android.launcher3.icons.cache.BaseIconCache;
+import com.android.launcher3.icons.cache.CachedObjectCachingLogic;
import com.android.launcher3.icons.cache.CachingLogic;
+import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.IconRequestInfo;
@@ -102,7 +103,6 @@
private final LauncherApps mLauncherApps;
private final UserCache mUserManager;
private final InstantAppResolver mInstantAppResolver;
- private final IconProvider mIconProvider;
private final CancellableTask mCancelledTask;
private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos;
@@ -112,14 +112,14 @@
public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName,
IconProvider iconProvider) {
super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
- idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */);
- mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false);
- mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context);
+ idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */, iconProvider);
+ mComponentWithLabelCachingLogic = new CachedObjectCachingLogic(
+ context, false /* loadIcons */, false /* addToMemCache */);
+ mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.INSTANCE;
mShortcutCachingLogic = new ShortcutCachingLogic();
mLauncherApps = mContext.getSystemService(LauncherApps.class);
mUserManager = UserCache.INSTANCE.get(mContext);
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
- mIconProvider = iconProvider;
mWidgetCategoryBitmapInfos = new SparseArray<>();
mCancelledTask = new CancellableTask(() -> null, MAIN_EXECUTOR, c -> { });
@@ -337,6 +337,9 @@
}
}
+ /**
+ * Loads and returns the icon for the provided object without adding it to memCache
+ */
public synchronized String getTitleNoCache(ComponentWithLabel info) {
CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info,
mComponentWithLabelCachingLogic, false /* usePackageIcon */,
@@ -629,12 +632,6 @@
info.getAppLabel());
}
- @Override
- @NonNull
- protected String getIconSystemState(String packageName) {
- return mIconProvider.getSystemStateForPackage(mSystemState, packageName);
- }
-
/**
* Interface for receiving itemInfo with high-res icon.
*/
diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
deleted file mode 100644
index de2269c..0000000
--- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.icons;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.LauncherActivityInfo;
-import android.os.Build;
-import android.os.UserHandle;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.Flags;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BaseIconFactory.IconOptions;
-import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.util.ResourceBasedOverride;
-
-/**
- * Caching logic for LauncherActivityInfo.
- */
-public class LauncherActivityCachingLogic
- implements CachingLogic<LauncherActivityInfo>, ResourceBasedOverride {
-
- /**
- * Creates and returns a new instance
- */
- public static LauncherActivityCachingLogic newInstance(Context context) {
- return Overrides.getObject(LauncherActivityCachingLogic.class, context,
- R.string.launcher_activity_logic_class);
- }
-
- @NonNull
- @Override
- public ComponentName getComponent(@NonNull LauncherActivityInfo object) {
- return object.getComponentName();
- }
-
- @NonNull
- @Override
- public UserHandle getUser(@NonNull LauncherActivityInfo object) {
- return object.getUser();
- }
-
- @NonNull
- @Override
- public CharSequence getLabel(@NonNull LauncherActivityInfo object) {
- return object.getLabel();
- }
-
- @NonNull
- @Override
- public BitmapInfo loadIcon(@NonNull Context context, @NonNull LauncherActivityInfo object) {
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
- IconOptions iconOptions = new IconOptions().setUser(object.getUser());
- iconOptions.mIsArchived = Flags.useNewIconForArchivedApps()
- && Build.VERSION.SDK_INT >= 35
- && object.getActivityInfo().isArchived;
- return li.createBadgedIconBitmap(
- LauncherAppState.getInstance(context)
- .getIconProvider()
- .getIcon(object, li.mFillResIconDpi),
- iconOptions
- );
- }
- }
-}
diff --git a/src/com/android/launcher3/icons/Legacy.kt b/src/com/android/launcher3/icons/Legacy.kt
new file mode 100644
index 0000000..3bf3bb2
--- /dev/null
+++ b/src/com/android/launcher3/icons/Legacy.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.launcher3.icons
+
+import com.android.launcher3.icons.cache.CachedObject
+
+/**
+ * This files contains some definitions used during refactoring to avoid breaking changes.
+ *
+ * TODO(b/366237794) remove this file once refactoring is complete
+ */
+
+/** Temporary interface to allow easier refactoring */
+interface ComponentWithLabel : CachedObject<IconCache>
+
+/** Temporary interface to allow easier refactoring */
+interface ComponentWithLabelAndIcon : ComponentWithLabel
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
index f40eda6..7bb39e1 100644
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
@@ -33,6 +33,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.icons.BaseIconFactory.IconOptions;
+import com.android.launcher3.icons.cache.BaseIconCache;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Themes;
@@ -72,7 +73,8 @@
@NonNull
@Override
- public BitmapInfo loadIcon(@NonNull Context context, @NonNull ShortcutInfo info) {
+ public BitmapInfo loadIcon(@NonNull Context context, @NonNull BaseIconCache cache,
+ @NonNull ShortcutInfo info) {
try (LauncherIcons li = LauncherIcons.obtain(context)) {
Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
context, info, LauncherAppState.getIDP(context).fillResIconDpi);
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 64ebbf3..1f60f13 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -223,7 +223,8 @@
if (DEBUG) {
Log.w(TAG, "updatePromiseInstallInfo: removing app due to install"
+ " failure and appInfo not startable."
- + " package=" + appInfo.getTargetPackage());
+ + " package=" + appInfo.getTargetPackage()
+ + ", user=" + user);
}
removeApp(i);
}
@@ -319,7 +320,8 @@
if (!findActivity(matches, applicationInfo.componentName)) {
if (DEBUG) {
Log.w(TAG, "Changing shortcut target due to app component name change."
- + " package=" + packageName);
+ + " component=" + applicationInfo.componentName
+ + ", user=" + user);
}
removeApp(i);
}
@@ -346,8 +348,9 @@
} else {
// Remove all data for this package.
if (DEBUG) {
- Log.w(TAG, "updatePromiseInstallInfo: no Activities matched updated package,"
- + " removing all apps from package=" + packageName);
+ Log.w(TAG, "updatePackage: no Activities matched updated package,"
+ + " removing any AppInfo with package=" + packageName
+ + ", user=" + user);
}
for (int i = data.size() - 1; i >= 0; i--) {
final AppInfo applicationInfo = data.get(i);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 605accf..609846f 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -70,11 +70,11 @@
import com.android.launcher3.folder.FolderNameInfos;
import com.android.launcher3.folder.FolderNameProvider;
import com.android.launcher3.icons.ComponentWithLabelAndIcon;
-import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.LauncherActivityCachingLogic;
import com.android.launcher3.icons.ShortcutCachingLogic;
+import com.android.launcher3.icons.cache.CachedObjectCachingLogic;
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
+import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.AppPairInfo;
@@ -298,7 +298,7 @@
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
setIgnorePackages(updateHandler);
updateHandler.updateIcons(allActivityList,
- LauncherActivityCachingLogic.newInstance(mApp.getContext()),
+ LauncherActivityCachingLogic.INSTANCE,
mApp.getModel()::onPackageIconsUpdated);
logASplit("update icon cache");
@@ -360,7 +360,7 @@
}
updateHandler.updateIcons(allWidgetsList,
- new ComponentWithIconCachingLogic(mApp.getContext(), true),
+ new CachedObjectCachingLogic(mApp.getContext()),
mApp.getModel()::onWidgetLabelsUpdated);
logASplit("save widgets in icon cache");
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 2febb22..5464afe 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -119,7 +119,8 @@
final HashMap<String, List<LauncherActivityInfo>> activitiesLists = new HashMap<>();
if (DEBUG) {
Log.d(TAG, "Package updated: mOp=" + getOpString()
- + " packages=" + Arrays.toString(packages));
+ + " packages=" + Arrays.toString(packages)
+ + ", user=" + mUser);
}
switch (mOp) {
case OP_ADD: {
diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java
index 667136a..47afeef 100644
--- a/src/com/android/launcher3/pm/PinRequestHelper.java
+++ b/src/com/android/launcher3/pm/PinRequestHelper.java
@@ -77,8 +77,9 @@
WorkspaceItemInfo info = new WorkspaceItemInfo(si, context);
// Apply the unbadged icon synchronously using the caching logic directly and
// fetch the actual icon asynchronously.
- info.bitmap = new ShortcutCachingLogic().loadIcon(context, si);
- LauncherAppState.getInstance(context).getModel().updateAndBindWorkspaceItem(info, si);
+ LauncherAppState app = LauncherAppState.getInstance(context);
+ info.bitmap = new ShortcutCachingLogic().loadIcon(context, app.getIconCache(), si);
+ app.getModel().updateAndBindWorkspaceItem(info, si);
return info;
} else {
return null;
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 1b245ab..63c9d94 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -1,5 +1,6 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
@@ -41,6 +42,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.Snackbar;
import com.android.launcher3.widget.WidgetsBottomSheet;
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
@@ -336,6 +338,14 @@
mTarget.getStatsLogManager().logger()
.withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP);
+ if (Flags.enableDismissPredictionUndo()) {
+ Snackbar.show(mTarget,
+ view.getContext().getString(R.string.item_removed), R.string.undo,
+ () -> { }, () ->
+ mTarget.getStatsLogManager().logger()
+ .withItemInfo(mItemInfo)
+ .log(LAUNCHER_DISMISS_PREDICTION_UNDO));
+ }
}
}
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 6ff51ca..82229f8 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -24,7 +24,6 @@
import com.android.launcher3.BubbleTextView
import com.android.launcher3.BuildConfig
import com.android.launcher3.allapps.BaseAllAppsAdapter
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.util.CancellableTask
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
@@ -78,7 +77,7 @@
ActivityContextDelegate(
context.createConfigurationContext(context.resources.configuration),
Themes.getActivityThemeRes(context),
- context
+ context,
)
// Because we perform onCreateViewHolder() on worker thread, we need a separate
@@ -91,7 +90,7 @@
context,
context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext),
null,
- null
+ null,
) {
override fun setAppsPerRow(appsPerRow: Int) = Unit
@@ -124,7 +123,7 @@
for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
putRecycledView(viewHolders[i])
}
- }
+ },
)
mCancellableTask = task
VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
@@ -144,18 +143,15 @@
* app icons plus [EXTRA_ICONS_COUNT] is the magic minimal count of app icons to preinflate to
* suffice fast scrolling.
*
- * Note that if [FeatureFlags.ALL_APPS_GONE_VISIBILITY] is enabled, we need to preinfate extra
- * app icons in size of one all apps pages, so that opening all apps don't need to inflate app
- * icons.
+ * Note that we need to preinfate extra app icons in size of one all apps pages, so that opening
+ * all apps don't need to inflate app icons.
*/
fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
var targetPreinflateCount =
PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
EXTRA_ICONS_COUNT
- if (FeatureFlags.ALL_APPS_GONE_VISIBILITY.get()) {
- val grid = ActivityContext.lookupContext<T>(context).deviceProfile
- targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns
- }
+ val grid = ActivityContext.lookupContext<T>(context).deviceProfile
+ targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns
if (hasWorkProfile) {
targetPreinflateCount *= 2
}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 072bcdf..dff9a07 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -195,6 +195,13 @@
}
/**
+ * Handles info change for launcher visibility.
+ */
+ public static void handleInfoChangeForLauncherVisibilityChanged(Context context) {
+ INSTANCE.get(context).handleInfoChange(context.getDisplay());
+ }
+
+ /**
* Enables transient taskbar status for tests.
*/
@VisibleForTesting
@@ -217,6 +224,13 @@
return INSTANCE.get(context).getInfo().isPinnedTaskbar();
}
+ /**
+ * Returns whether the taskbar is forced to be pinned when home is visible.
+ */
+ public static boolean showLockedTaskbarOnHome(Context context) {
+ return INSTANCE.get(context).getInfo().showLockedTaskbarOnHome();
+ }
+
@Override
public void close() {
mDestroyed = true;
@@ -345,7 +359,8 @@
}
if ((newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned)
|| (newInfo.mIsTaskbarPinnedInDesktopMode
- != oldInfo.mIsTaskbarPinnedInDesktopMode)) {
+ != oldInfo.mIsTaskbarPinnedInDesktopMode)
+ || newInfo.isPinnedTaskbar() != oldInfo.isPinnedTaskbar()) {
change |= CHANGE_TASKBAR_PINNING;
}
if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) {
@@ -399,6 +414,9 @@
private final boolean mIsInDesktopMode;
+ private final boolean mShowLockedTaskbarOnHome;
+ private final boolean mIsHomeVisible;
+
public Info(Context displayInfoContext) {
/* don't need system overrides for external displays */
this(displayInfoContext, new WindowManagerProxy(), new ArrayMap<>());
@@ -460,6 +478,8 @@
mIsTaskbarPinnedInDesktopMode = LauncherPrefs.get(displayInfoContext).get(
TASKBAR_PINNING_IN_DESKTOP_MODE);
mIsInDesktopMode = wmProxy.isInDesktopMode();
+ mShowLockedTaskbarOnHome = wmProxy.showLockedTaskbarOnHome(displayInfoContext);
+ mIsHomeVisible = wmProxy.isHomeVisible(displayInfoContext);
}
/**
@@ -476,6 +496,10 @@
return sTransientTaskbarStatusForTests;
}
if (enableTaskbarPinning()) {
+ // If Launcher is visible on the freeform display, ensure the taskbar is pinned.
+ if (mShowLockedTaskbarOnHome && mIsHomeVisible) {
+ return false;
+ }
if (mIsInDesktopMode) {
return !mIsTaskbarPinnedInDesktopMode;
}
@@ -543,6 +567,13 @@
return TYPE_PHONE;
}
}
+
+ /**
+ * Returns whether the taskbar is forced to be pinned when home is visible.
+ */
+ public boolean showLockedTaskbarOnHome() {
+ return mShowLockedTaskbarOnHome;
+ }
}
/**
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 1a0f9a0..63f14bd 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -35,6 +35,9 @@
/**
* Utility class for defining singletons which are initiated on main thread.
+ *
+ * TODO(b/361850561): Do not delete MainThreadInitializedObject until we find a way to
+ * unregister and understand how singleton objects are destroyed in dagger graph.
*/
public class MainThreadInitializedObject<T extends SafeCloseable> {
diff --git a/src/com/android/launcher3/util/MultiTranslateDelegate.java b/src/com/android/launcher3/util/MultiTranslateDelegate.java
index 84ef445..38c87c8 100644
--- a/src/com/android/launcher3/util/MultiTranslateDelegate.java
+++ b/src/com/android/launcher3/util/MultiTranslateDelegate.java
@@ -37,6 +37,7 @@
public static final int INDEX_TASKBAR_ALIGNMENT_ANIM = 3;
public static final int INDEX_TASKBAR_REVEAL_ANIM = 4;
public static final int INDEX_TASKBAR_PINNING_ANIM = 5;
+ public static final int INDEX_NAV_BAR_ANIM = 6;
// Affect all items inside of a MultipageCellLayout
public static final int INDEX_CELLAYOUT_MULTIPAGE_SPACING = 3;
@@ -47,7 +48,7 @@
// Specific for hotseat items when adjusting for bubbles
public static final int INDEX_BUBBLE_ADJUSTMENT_ANIM = 3;
- public static final int COUNT = 6;
+ public static final int COUNT = 7;
private final MultiPropertyFactory<View> mTranslationX;
private final MultiPropertyFactory<View> mTranslationY;
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 0817c0a..22ecf68 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -122,6 +122,20 @@
}
/**
+ * Returns if the pinned taskbar should be shown when home is visible.
+ */
+ public boolean showLockedTaskbarOnHome(Context displayInfoContext) {
+ return false;
+ }
+
+ /**
+ * Returns if the home is visible.
+ */
+ public boolean isHomeVisible(Context context) {
+ return false;
+ }
+
+ /**
* Returns the real bounds for the provided display after applying any insets normalization
*/
public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 63648dd..6fd18be 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -355,7 +355,10 @@
if (!sectionName.equals(mPopupSectionName)) {
mPopupSectionName = sectionName;
mPopupView.setText(sectionName);
- performHapticFeedback(CLOCK_TICK);
+ // AllApps haptics are taken care of by AllAppsFastScrollHelper.
+ if (mFastScrollerLocation != ALL_APPS_SCROLLER) {
+ performHapticFeedback(CLOCK_TICK);
+ }
}
animatePopupVisibility(!TextUtils.isEmpty(sectionName));
mLastTouchY = boundedY;
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
index 2e5e251..a2fac46 100644
--- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -29,7 +29,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import java.util.ArrayList;
import java.util.List;
@@ -73,7 +72,7 @@
/** Check if the app widget is in the deny list. */
public static boolean isRoundedCornerEnabled() {
- return Utilities.ATLEAST_S && FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get();
+ return Utilities.ATLEAST_S;
}
/**
diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
index 4d7f937..63d87e8 100644
--- a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
+++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java
@@ -18,12 +18,10 @@
import dagger.Component;
-import javax.inject.Singleton;
-
/**
* Root component for Dagger injection for Launcher AOSP.
*/
-@Singleton
+@LauncherAppSingleton
@Component
public interface LauncherAppComponent extends LauncherBaseAppComponent {
/** Builder for aosp LauncherAppComponent. */
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index ea58136..d7dd40b 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -170,7 +170,7 @@
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
- public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
+
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
diff --git a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
similarity index 98%
rename from tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
rename to tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
index ac2c553..d2103ae 100644
--- a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-class FloatingHeaderViewTests {
+class FloatingHeaderViewTest {
@get:Rule val mSetFlagsRule = SetFlagsRule()
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 41effa2..d4e4bd2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -38,6 +38,8 @@
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import kotlin.math.min
import org.junit.Before
import org.junit.Test
@@ -111,6 +113,7 @@
whenever(windowManagerProxy.getRealBounds(any(), any())).thenAnswer { i ->
bounds[i.getArgument<CachedDisplayInfo>(1).rotation]
}
+ whenever(windowManagerProxy.showLockedTaskbarOnHome(any())).thenReturn(false)
whenever(windowManagerProxy.getNavigationMode(any())).thenReturn(NavigationMode.NO_BUTTON)
// Mock context
@@ -180,4 +183,20 @@
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
+
+ @Test
+ @UiThreadTest
+ fun testTaskbarPinningChangeInLockedTaskbarChange() {
+ whenever(windowManagerProxy.showLockedTaskbarOnHome(any())).thenReturn(true)
+ whenever(windowManagerProxy.isHomeVisible(any())).thenReturn(true)
+ whenever(windowManagerProxy.isInDesktopMode()).thenReturn(false)
+ whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
+ DisplayController.enableTaskbarModePreferenceForTests(true)
+
+ assertTrue(displayController.getInfo().isTransientTaskbar())
+ displayController.handleInfoChange(display)
+ verify(displayInfoChangeListener)
+ .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
+ assertFalse(displayController.getInfo().isTransientTaskbar())
+ }
}
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 76c1948..8fe77ac 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -197,7 +197,6 @@
@PlatinumTest(focusArea = "launcher")
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/343953783
public void testDragAppIcon() {
final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index dcfcad5..f54668c 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -19,19 +19,26 @@
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
+import static com.android.launcher3.Flags.FLAG_ENABLE_DISMISS_PREDICTION_UNDO;
import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -50,8 +57,13 @@
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.R;
import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -61,8 +73,9 @@
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
import com.android.launcher3.util.LauncherMultivalentJUnit;
import com.android.launcher3.util.TestSandboxModelContextWrapper;
+import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.UserIconInfo;
-import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.views.Snackbar;
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
@@ -72,6 +85,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -88,25 +102,31 @@
private PrivateProfileManager mPrivateProfileManager;
private WidgetPickerDataProvider mWidgetPickerDataProvider;
private AppInfo mAppInfo;
+
@Mock UserCache mUserCache;
@Mock ApiWrapper mApiWrapper;
- @Mock BaseDragLayer mBaseDragLayer;
@Mock UserIconInfo mUserIconInfo;
@Mock LauncherActivityInfo mLauncherActivityInfo;
@Mock ApplicationInfo mApplicationInfo;
@Mock Intent mIntent;
+ @Mock StatsLogManager mStatsLogManager;
+ @Mock(answer = Answers.RETURNS_SELF) StatsLogger mStatsLogger;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper);
- mTestContext = new TestSandboxModelContextWrapper(mSandboxContext);
- mView = new View(mSandboxContext);
- spyOn(mTestContext);
+ mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
+ @Override
+ public StatsLogManager getStatsLogManager() {
+ return mStatsLogManager;
+ }
+ };
spyOn(mSandboxContext);
- doReturn(mBaseDragLayer).when(mTestContext).getDragLayer();
+ doReturn(mStatsLogger).when(mStatsLogManager).logger();
+ mView = new View(mTestContext);
mItemInfo = new ItemInfo();
LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class);
@@ -114,7 +134,6 @@
when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo);
when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo);
- when(mBaseDragLayer.getChildCount()).thenReturn(0);
mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager();
spyOn(mPrivateProfileManager);
when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
@@ -168,6 +187,7 @@
}
@Test
+ @DisableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
public void testDontSuggestAppForPredictedItem() {
mAppInfo = new AppInfo();
mAppInfo.componentName = new ComponentName(mTestContext, getClass());
@@ -176,7 +196,36 @@
SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
.getShortcut(mTestContext, mAppInfo, mView);
assertNotNull(systemShortcut);
- systemShortcut.onClick(mView);
+
+ TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
+ assertFalse(AbstractFloatingView.hasOpenView(mTestContext, TYPE_SNACKBAR));
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
+ public void testDontSuggestAppForPredictedItemWithUndo() {
+ mAppInfo = new AppInfo();
+ mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+ mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
+ assertTrue(mAppInfo.isPredictedItem());
+ SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
+ .getShortcut(mTestContext, mAppInfo, mView);
+ assertNotNull(systemShortcut);
+
+ TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
+
+ // Undo bar shown
+ Snackbar snackbar = AbstractFloatingView.getOpenView(mTestContext, TYPE_SNACKBAR);
+ assertNotNull(snackbar);
+ reset(mStatsLogger);
+ TestUtil.runOnExecutorSync(MAIN_EXECUTOR, snackbar.findViewById(
+ R.id.action)::performClick);
+ verify(mStatsLogger).log(eq(LAUNCHER_DISMISS_PREDICTION_UNDO));
}
@Test
diff --git a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
new file mode 100644
index 0000000..a6de607
--- /dev/null
+++ b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.tablet
+
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import com.android.launcher3.Launcher
+import com.android.launcher3.ui.AbstractLauncherUiTest
+import junit.framework.TestCase.assertFalse
+import junit.framework.TestCase.assertTrue
+import org.junit.Test
+
+class TaplIsTabletTest : AbstractLauncherUiTest<Launcher>() {
+
+ /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
+ @Test
+ @AllowedDevices(
+ DeviceProduct.CF_FOLDABLE,
+ DeviceProduct.CF_TABLET,
+ DeviceProduct.TANGORPRO,
+ DeviceProduct.FELIX,
+ DeviceProduct.COMET,
+ )
+ fun isTabletShouldBeTrue() {
+ assertTrue(mLauncher.isTablet)
+ }
+
+ /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
+ @Test
+ @AllowedDevices(DeviceProduct.CF_PHONE, DeviceProduct.CHEETAH)
+ fun isTabletShouldBeFalse() {
+ assertFalse(mLauncher.isTablet)
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index b2e413d..b38dd4b 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -45,7 +45,6 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
import org.junit.After;
@@ -147,7 +146,6 @@
// Staging; will be promoted to presubmit if stable
@Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
- @ScreenRecord
@Test
public void toggleWorks() {
assumeTrue(mWorkProfileSetupSuccessful);
@@ -195,7 +193,6 @@
}
- @ScreenRecord // b/322823478
@Test
public void testEdu() {
assumeTrue(mWorkProfileSetupSuccessful);
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index 20c5a25..2edd129 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -164,7 +164,6 @@
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/352130094
public void testDragIconToPage2() {
Workspace workspace = mLauncher.getWorkspace();
@@ -242,7 +241,6 @@
});
}
- @ScreenRecordRule.ScreenRecord // b/329935119
@Test
@PortraitLandscape
public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index d3c423e..21e93c5 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -55,6 +55,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.text.TextUtils;
import android.util.Log;
import android.view.InputDevice;
@@ -524,16 +525,19 @@
Closable addContextLayer(String piece) {
mDiagnosticContext.addLast(piece);
+ Trace.beginSection("Context: " + piece);
log("Entering context: " + piece);
return () -> {
+ Trace.endSection();
log("Leaving context: " + piece);
mDiagnosticContext.removeLast();
};
}
public void dumpViewHierarchy() {
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
+ Trace.beginSection("dumpViewHierarchy");
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
mDevice.dumpWindowHierarchy(stream);
stream.flush();
stream.close();
@@ -542,6 +546,8 @@
}
} catch (IOException e) {
Log.e(TAG, "error dumping XML to logcat", e);
+ } finally {
+ Trace.endSection();
}
}
@@ -621,15 +627,20 @@
*/
public void checkForAnomaly(
boolean ignoreNavmodeChangeStates, boolean ignoreOnlySystemUiViews) {
- if (mTestAnomalyChecker != null) mTestAnomalyChecker.run();
+ try {
+ Trace.beginSection("checkForAnomaly");
+ if (mTestAnomalyChecker != null) mTestAnomalyChecker.run();
- final String systemAnomalyMessage =
- getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
- if (systemAnomalyMessage != null) {
- if (mOnFailure != null) mOnFailure.run();
- Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
- "http://go/tapl : Tests are broken by a non-Launcher system error: "
- + systemAnomalyMessage, false)));
+ final String systemAnomalyMessage =
+ getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
+ if (systemAnomalyMessage != null) {
+ if (mOnFailure != null) mOnFailure.run();
+ Assert.fail(formatSystemHealthMessage(formatErrorWithEvents(
+ "http://go/tapl : Tests are broken by a non-Launcher system error: "
+ + systemAnomalyMessage, false)));
+ }
+ } finally {
+ Trace.endSection();
}
}
@@ -1005,16 +1016,20 @@
}
public void waitForLauncherInitialized() {
- for (int i = 0; i < 100; ++i) {
- if (getTestInfo(
- TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED).
- getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD)) {
- return;
+ try {
+ Trace.beginSection("waitForLauncherInitialized");
+ for (int i = 0; i < 100; ++i) {
+ if (getTestInfo(TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED).getBoolean(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD)) {
+ return;
+ }
+ SystemClock.sleep(100);
}
- SystemClock.sleep(100);
+ checkForAnomaly();
+ fail("Launcher didn't initialize");
+ } finally {
+ Trace.endSection();
}
- checkForAnomaly();
- fail("Launcher didn't initialize");
}
public boolean isLauncherActivityStarted() {
@@ -1259,8 +1274,13 @@
}
boolean isLauncherVisible() {
- mDevice.waitForIdle();
- return hasLauncherObject(getAnyObjectSelector());
+ try {
+ Trace.beginSection("isLauncherVisible");
+ mDevice.waitForIdle();
+ return hasLauncherObject(getAnyObjectSelector());
+ } finally {
+ Trace.endSection();
+ }
}
boolean isLauncherContainerVisible() {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 5433fa7..9a8d952 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -282,7 +282,7 @@
* Returns whether the given String is contained in this Task's contentDescription. Also returns
* true if both Strings are null.
*
- * TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed.
+ * TODO(b/342627272): remove Nullable support once the bug causing it to be null is fixed.
*/
public boolean containsContentDescription(@Nullable String expected,
OverviewSplitTask overviewSplitTask) {