Merge "Disable 3-finger workspace scroll" into udc-dev
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 225bdcc..599095b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -300,6 +300,8 @@
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
<dimen name="transient_taskbar_stashed_size">32dp</dimen>
<dimen name="transient_taskbar_all_apps_button_translation_x_offset">4dp</dimen>
+ <dimen name="transient_taskbar_stash_spring_velocity_dp_per_s">400dp</dimen>
+
<!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
<dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
<!-- Taskbar swipe up thresholds -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index 48352a2..331184a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -65,4 +65,10 @@
/** Callback invoked when a popup is shown or closed within this context. */
public abstract void onPopupVisibilityChanged(boolean isVisible);
+
+ /**
+ * Callback invoked when user attempts to split the screen through a long-press menu in Taskbar
+ * or AllApps.
+ */
+ public abstract void onSplitScreenMenuButtonClicked();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 089e069..a9ce61a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -82,7 +82,6 @@
};
// Initialized in init.
- private TaskbarKeyguardController mKeyguardController;
private final TaskbarLauncherStateController
mTaskbarLauncherStateController = new TaskbarLauncherStateController();
@@ -97,11 +96,12 @@
mTaskbarLauncherStateController.init(mControllers, mLauncher);
mLauncher.setTaskbarUIController(this);
- mKeyguardController = taskbarControllers.taskbarKeyguardController;
onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
onStashedInAppChanged(mLauncher.getDeviceProfile());
+ mTaskbarLauncherStateController.onChangeScreenState(
+ mControllers.getSharedState().sysuiStateFlags, true /* fromInit */);
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
}
@@ -119,7 +119,7 @@
@Override
protected boolean isTaskbarTouchable() {
return !(mTaskbarLauncherStateController.isAnimatingToLauncher()
- && mTaskbarLauncherStateController.goingToAlignedLauncherState());
+ && mTaskbarLauncherStateController.isTaskbarAlignedWithHotseat());
}
public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) {
@@ -167,15 +167,6 @@
@Nullable
private Animator onLauncherResumedOrPaused(
boolean isResumed, boolean fromInit, boolean startAnimation, int duration) {
- if (mKeyguardController.isScreenOff()) {
- if (!isResumed) {
- return null;
- } else {
- // Resuming implicitly means device unlocked
- mKeyguardController.setScreenOn();
- }
- }
-
// Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
// avoid updating taskbar state in that situation (when it's non-interactive -- or
// "background") to avoid premature animations.
@@ -328,6 +319,11 @@
}
@Override
+ public void onChangeScreenState(int screenState) {
+ mTaskbarLauncherStateController.onChangeScreenState(screenState, false /* fromInit */);
+ }
+
+ @Override
public boolean isIconAlignedWithHotseat() {
return mTaskbarLauncherStateController.isIconAlignedWithHotseat();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index f082fc6..48b3f72 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -84,6 +84,9 @@
private boolean mIsStashed;
private boolean mTaskbarHidden;
+ private float mTranslationYForSwipe;
+ private float mTranslationYForStash;
+
public StashedHandleViewController(TaskbarActivityContext activity,
StashedHandleView stashedHandleView) {
mActivity = activity;
@@ -254,7 +257,20 @@
* Sets the translation of the stashed handle during the swipe up gesture.
*/
protected void setTranslationYForSwipe(float transY) {
- mStashedHandleView.setTranslationY(transY);
+ mTranslationYForSwipe = transY;
+ updateTranslationY();
+ }
+
+ /**
+ * Sets the translation of the stashed handle during the spring on stash animation.
+ */
+ protected void setTranslationYForStash(float transY) {
+ mTranslationYForStash = transY;
+ updateTranslationY();
+ }
+
+ private void updateTranslationY() {
+ mStashedHandleView.setTranslationY(mTranslationYForSwipe + mTranslationYForStash);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 39a5ad4..6041192 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
@@ -56,7 +57,6 @@
import android.view.RoundedCorner;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import android.widget.Toast;
@@ -80,6 +80,7 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
@@ -234,6 +235,7 @@
new TaskbarInsetsController(this),
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
+ new TaskbarSpringOnStashController(this),
isDesktopMode
? new DesktopTaskbarRecentAppsController(this)
: TaskbarRecentAppsController.DEFAULT,
@@ -525,6 +527,16 @@
setTaskbarWindowFocusable(isVisible);
}
+ @Override
+ public void onSplitScreenMenuButtonClicked() {
+ PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(this);
+ if (popup != null) {
+ popup.addOnCloseCallback(() -> {
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
+ });
+ }
+ }
+
/**
* Sets a new data-source for this taskbar instance
*/
@@ -579,6 +591,9 @@
mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
(systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
+
+ mControllers.uiController.onChangeScreenState(
+ systemUiStateFlags & SYSUI_STATE_SCREEN_STATE_MASK);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 3375877..82b455d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -35,6 +35,7 @@
val lastDrawnTransientRect = RectF()
var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
var translationYForSwipe = 0f
+ var translationYForStash = 0f
private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -136,7 +137,9 @@
val bottom =
canvas.height - bottomMargin +
bottomMarginProgress +
- (-mapRange(1f - progress, 0f, stashedHandleHeight / 2f) + translationYForSwipe)
+ translationYForSwipe +
+ translationYForStash +
+ -mapRange(1f - progress, 0f, stashedHandleHeight / 2f)
// Draw shadow.
val shadowAlpha =
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 931d79f..a6da56d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -57,6 +57,7 @@
public final VoiceInteractionWindowController voiceInteractionWindowController;
public final TaskbarRecentAppsController taskbarRecentAppsController;
public final TaskbarTranslationController taskbarTranslationController;
+ public final TaskbarSpringOnStashController taskbarSpringOnStashController;
public final TaskbarOverlayController taskbarOverlayController;
public final TaskbarEduTooltipController taskbarEduTooltipController;
public final KeyboardQuickSwitchController keyboardQuickSwitchController;
@@ -103,6 +104,7 @@
TaskbarInsetsController taskbarInsetsController,
VoiceInteractionWindowController voiceInteractionWindowController,
TaskbarTranslationController taskbarTranslationController,
+ TaskbarSpringOnStashController taskbarSpringOnStashController,
TaskbarRecentAppsController taskbarRecentAppsController,
TaskbarEduTooltipController taskbarEduTooltipController,
KeyboardQuickSwitchController keyboardQuickSwitchController) {
@@ -127,6 +129,7 @@
this.taskbarInsetsController = taskbarInsetsController;
this.voiceInteractionWindowController = voiceInteractionWindowController;
this.taskbarTranslationController = taskbarTranslationController;
+ this.taskbarSpringOnStashController = taskbarSpringOnStashController;
this.taskbarRecentAppsController = taskbarRecentAppsController;
this.taskbarEduTooltipController = taskbarEduTooltipController;
this.keyboardQuickSwitchController = keyboardQuickSwitchController;
@@ -149,6 +152,7 @@
taskbarScrimViewController.init(this);
taskbarUnfoldAnimationController.init(this);
taskbarKeyguardController.init(navbarButtonsViewController);
+ taskbarSpringOnStashController.init(this);
stashedHandleViewController.init(this);
taskbarStashController.init(this, sharedState.setupUIVisible);
taskbarEduController.init(this);
@@ -209,7 +213,6 @@
uiController.onDestroy();
rotationButtonController.onDestroy();
taskbarDragLayerController.onDestroy();
- taskbarKeyguardController.onDestroy();
taskbarUnfoldAnimationController.onDestroy();
taskbarViewController.onDestroy();
stashedHandleViewController.onDestroy();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 58d6244..6b9297d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -184,6 +184,14 @@
invalidate();
}
+ /*
+ * Sets the translation of the background during the spring on stash animation.
+ */
+ protected void setBackgroundTranslationYForStash(float translationY) {
+ mBackgroundRenderer.setTranslationYForStash(translationY);
+ invalidate();
+ }
+
/** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
protected RectF getLastDrawnTransientRect() {
return mBackgroundRenderer.getLastDrawnTransientRect();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 7c3d14d..2badc24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -161,6 +161,13 @@
mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
}
+ /**
+ * Sets the translation of the background during the spring on stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mTaskbarDragLayer.setBackgroundTranslationYForStash(transY);
+ }
+
private void updateBackgroundOffset() {
mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index 93ba4eb..4e390f1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -1,19 +1,20 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.systemui.shared.system.QuickStepContract.SCREEN_STATE_OFF;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_STATE_MASK;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import android.app.KeyguardManager;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.util.ScreenOnTracker;
-import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
import com.android.systemui.shared.system.QuickStepContract;
import java.io.PrintWriter;
@@ -23,36 +24,35 @@
*/
public class TaskbarKeyguardController implements TaskbarControllers.LoggableTaskbarController {
- private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING |
- SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING |
- SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED |
- SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+ private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING
+ | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING
+ | SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED
+ | SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
+ | SYSUI_STATE_SCREEN_STATE_MASK;
- private final ScreenOnListener mScreenOnListener;
private final TaskbarActivityContext mContext;
private int mKeyguardSysuiFlags;
private boolean mBouncerShowing;
private NavbarButtonsViewController mNavbarButtonsViewController;
private final KeyguardManager mKeyguardManager;
- private boolean mIsScreenOff;
public TaskbarKeyguardController(TaskbarActivityContext context) {
mContext = context;
- mScreenOnListener = isOn -> {
- if (!isOn) {
- mIsScreenOff = true;
- AbstractFloatingView.closeOpenViews(mContext, false, TYPE_ALL);
- }
- };
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
}
public void init(NavbarButtonsViewController navbarButtonUIController) {
mNavbarButtonsViewController = navbarButtonUIController;
- ScreenOnTracker.INSTANCE.get(mContext).addListener(mScreenOnListener);
}
public void updateStateForSysuiFlags(int systemUiStateFlags) {
+ int interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
+ if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
+ // No change in keyguard relevant flags
+ return;
+ }
+ mKeyguardSysuiFlags = interestingKeyguardFlags;
+
boolean bouncerShowing = (systemUiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0;
boolean keyguardShowing = (systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING)
!= 0;
@@ -60,11 +60,6 @@
(systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0;
boolean dozing = (systemUiStateFlags & SYSUI_STATE_DEVICE_DOZING) != 0;
- int interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
- if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
- return;
- }
- mKeyguardSysuiFlags = interestingKeyguardFlags;
mBouncerShowing = bouncerShowing;
@@ -72,19 +67,17 @@
keyguardOccluded);
updateIconsForBouncer();
- if (keyguardShowing) {
- AbstractFloatingView.closeOpenViews(mContext, true, TYPE_ALL);
+ boolean screenOffOrTransitioningOff = (systemUiStateFlags & SYSUI_STATE_SCREEN_ON) == 0;
+ boolean closeFloatingViews = keyguardShowing || screenOffOrTransitioningOff;
+
+ if (closeFloatingViews) {
+ // animate the closing of the views, unless the screen is already fully turned off.
+ boolean animateViewClosing =
+ (systemUiStateFlags & SYSUI_STATE_SCREEN_STATE_MASK) != SCREEN_STATE_OFF;
+ AbstractFloatingView.closeOpenViews(mContext, animateViewClosing, TYPE_ALL);
}
}
- public boolean isScreenOff() {
- return mIsScreenOff;
- }
-
- public void setScreenOn() {
- mIsScreenOff = false;
- }
-
/**
* Hides/shows taskbar when keyguard is up
*/
@@ -95,9 +88,6 @@
mNavbarButtonsViewController.setBackForBouncer(showBackForBouncer);
}
- public void onDestroy() {
- ScreenOnTracker.INSTANCE.get(mContext).removeListener(mScreenOnListener);
- }
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
@@ -106,6 +96,5 @@
pw.println(prefix + "\tmKeyguardSysuiFlags=" + QuickStepContract.getSystemUiStateString(
mKeyguardSysuiFlags));
pw.println(prefix + "\tmBouncerShowing=" + mBouncerShowing);
- pw.println(prefix + "\tmIsScreenOff=" + mIsScreenOff);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 7d5a400..93a0c11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -18,7 +18,10 @@
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
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;
import static com.android.systemui.animation.Interpolators.EMPHASIZED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_ON;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -53,16 +56,43 @@
* Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
* the task bar accordingly.
*/
- public class TaskbarLauncherStateController {
+public class TaskbarLauncherStateController {
private static final String TAG = TaskbarLauncherStateController.class.getSimpleName();
private static final boolean DEBUG = false;
+ /** Launcher activity is resumed and focused. */
public static final int FLAG_RESUMED = 1 << 0;
- public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
- public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2;
- private static final int FLAGS_LAUNCHER = FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING;
+ /**
+ * A external transition / animation is running that will result in FLAG_RESUMED being set.
+ **/
+ public static final int FLAG_TRANSITION_TO_RESUMED = 1 << 1;
+
+ /**
+ * Set while the launcher state machine is performing a state transition, see {@link
+ * StateManager.StateListener}.
+ */
+ public static final int FLAG_LAUNCHER_IN_STATE_TRANSITION = 1 << 2;
+
+ /**
+ * Whether the screen is currently on, or is transitioning to be on.
+ *
+ * This is cleared as soon as the screen begins to transition off.
+ */
+ private static final int FLAG_SCREEN_ON = 1 << 3;
+
+ /**
+ * Captures whether the launcher was active at the time the FLAG_SCREEN_ON was cleared.
+ * Always cleared when FLAG_SCREEN_ON is set.
+ * <p>
+ * FLAG_RESUMED will be cleared when the screen is off, since all apps get paused at this point.
+ * Thus, this flag indicates whether the launcher will be shown when the screen gets turned on
+ * again.
+ */
+ private static final int FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF = 1 << 4;
+
+ private static final int FLAGS_LAUNCHER_ACTIVE = FLAG_RESUMED | FLAG_TRANSITION_TO_RESUMED;
/** Equivalent to an int with all 1s for binary operation purposes */
private static final int FLAGS_ALL = ~0;
@@ -115,12 +145,13 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
if (toState != mLauncherState) {
- // Treat FLAG_TRANSITION_STATE_RUNNING as a changed flag even if a previous
- // state transition was already running, so we update the new target.
- mPrevState &= ~FLAG_TRANSITION_STATE_RUNNING;
+ // Treat FLAG_LAUNCHER_IN_STATE_TRANSITION as a changed flag even if a
+ // previous state transition was already running, so we update the new
+ // target.
+ mPrevState &= ~FLAG_LAUNCHER_IN_STATE_TRANSITION;
mLauncherState = toState;
}
- updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
+ updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
if (!mShouldDelayLauncherStateAnim) {
if (toState == LauncherState.NORMAL) {
applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
@@ -133,7 +164,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
mLauncherState = finalState;
- updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
+ updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
applyState();
boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
@@ -159,9 +190,6 @@
resetIconAlignment();
mLauncher.getStateManager().addStateListener(mStateListener);
-
- // Initialize to the current launcher state
- updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
mLauncherState = launcher.getStateManager().getState();
applyState(0);
@@ -182,6 +210,12 @@
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
}
+ /**
+ * Creates a transition animation to the launcher activity.
+ *
+ * Warning: the resulting animation must be played, since this method has side effects on this
+ * controller's state.
+ */
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
// If going to overview, stash the task bar
@@ -197,7 +231,7 @@
}
stashController.updateStateForFlag(FLAG_IN_APP, false);
- updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
+ updateStateForFlag(FLAG_TRANSITION_TO_RESUMED, true);
animatorSet.play(stashController.createApplyStateAnimator(duration));
animatorSet.play(applyState(duration, false));
@@ -225,12 +259,30 @@
mShouldDelayLauncherStateAnim = shouldDelayLauncherStateAnim;
}
+ /** Screen state changed, see QuickStepContract.SCREEN_STATE_* values. */
+ public void onChangeScreenState(int screenState, boolean fromInit) {
+ final boolean prevScreenIsOn = hasAnyFlag(FLAG_SCREEN_ON);
+ final boolean currScreenIsOn = hasAnyFlag(screenState, SYSUI_STATE_SCREEN_ON);
+
+ if (prevScreenIsOn == currScreenIsOn) return;
+
+ updateStateForFlag(FLAG_SCREEN_ON, currScreenIsOn);
+ updateStateForFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
+ prevScreenIsOn && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
+
+ if (fromInit) {
+ applyState(0);
+ } else {
+ applyState();
+ }
+ }
+
/**
* Updates the proper flag to change the state of the task bar.
*
* Note that this only updates the flag. {@link #applyState()} needs to be called separately.
*
- * @param flag The flag to update.
+ * @param flag The flag to update.
* @param enabled Whether to enable the flag
*/
public void updateStateForFlag(int flag, boolean enabled) {
@@ -269,6 +321,19 @@
if (mPrevState == null || mPrevState != mState) {
// If this is our initial state, treat all flags as changed.
int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState;
+
+ if (DEBUG) {
+ String stateString;
+ if (mPrevState == null) {
+ stateString = getStateString(mState) + "(initial update)";
+ } else {
+ stateString = formatFlagChange(mState, mPrevState,
+ TaskbarLauncherStateController::getStateString);
+ }
+ Log.d(TAG, "applyState: " + stateString
+ + ", duration: " + duration
+ + ", start: " + start);
+ }
mPrevState = mState;
animator = onStateChangeApplied(changedFlags, duration, start);
}
@@ -276,26 +341,23 @@
}
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
- final boolean goingToLauncher = isInLauncher();
+ final boolean isInLauncher = isInLauncher();
final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
final float toAlignment = isIconAlignedWithHotseat ? 1 : 0;
boolean handleOpenFloatingViews = false;
if (DEBUG) {
- Log.d(TAG, "onStateChangeApplied - mState: " + getStateString(mState)
- + ", changedFlags: " + getStateString(changedFlags)
- + ", goingToLauncher: " + goingToLauncher
+ Log.d(TAG, "onStateChangeApplied - isInLauncher: " + isInLauncher
+ ", mLauncherState: " + mLauncherState
+ ", toAlignment: " + toAlignment);
}
AnimatorSet animatorSet = new AnimatorSet();
- // Add the state animation first to ensure FLAG_IN_STASHED_LAUNCHER_STATE is set and we can
- // determine whether goingToUnstashedLauncherStateChanged.
- if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
- boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
- playStateTransitionAnim(animatorSet, duration, committed);
+ if (hasAnyFlag(changedFlags, FLAG_LAUNCHER_IN_STATE_TRANSITION)) {
+ boolean launcherTransitionCompleted = !hasAnyFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION);
+ playStateTransitionAnim(animatorSet, duration, launcherTransitionCompleted);
- if (committed && mLauncherState == LauncherState.QUICK_SWITCH_FROM_HOME) {
+ if (launcherTransitionCompleted
+ && mLauncherState == LauncherState.QUICK_SWITCH_FROM_HOME) {
// We're about to be paused, set immediately to ensure seamless handoff.
updateStateForFlag(FLAG_RESUMED, false);
applyState(0 /* duration */);
@@ -306,37 +368,37 @@
}
}
- if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER)) {
+ if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER_ACTIVE)) {
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(Animator animation) {
- mIsAnimatingToLauncher = false;
- }
-
- @Override
public void onAnimationStart(Animator animation) {
- mIsAnimatingToLauncher = goingToLauncher;
+ mIsAnimatingToLauncher = isInLauncher;
TaskbarStashController stashController =
mControllers.taskbarStashController;
if (DEBUG) {
- Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !goingToLauncher);
+ Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !isInLauncher);
}
- stashController.updateStateForFlag(FLAG_IN_APP, !goingToLauncher);
+ stashController.updateStateForFlag(FLAG_IN_APP, !isInLauncher);
stashController.applyState(duration);
}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncher = false;
+ }
});
// Handle closing open popups when going home/overview
handleOpenFloatingViews = true;
}
- if (handleOpenFloatingViews && goingToLauncher) {
+
+ if (handleOpenFloatingViews && isInLauncher) {
AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext);
}
- float backgroundAlpha =
- goingToLauncher && mLauncherState.isTaskbarAlignedWithHotseat(mLauncher)
- ? 0 : 1;
+ float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
+
// Don't animate if background has reached desired value.
if (mTaskbarBackgroundAlpha.isAnimating()
|| mTaskbarBackgroundAlpha.value != backgroundAlpha) {
@@ -347,21 +409,20 @@
+ " -> " + backgroundAlpha + ": " + duration);
}
- boolean goingToLauncherIconNotAligned = goingToLauncher && !isIconAlignedWithHotseat;
- boolean notGoingToLauncherIconNotAligned = !goingToLauncher
- && !isIconAlignedWithHotseat;
- boolean goingToLauncherIconIsAligned = goingToLauncher && isIconAlignedWithHotseat;
+ boolean isInLauncherIconNotAligned = isInLauncher && !isIconAlignedWithHotseat;
+ boolean notInLauncherIconNotAligned = !isInLauncher && !isIconAlignedWithHotseat;
+ boolean isInLauncherIconIsAligned = isInLauncher && isIconAlignedWithHotseat;
float startDelay = 0;
// We want to delay the background from fading in so that the icons have time to move
// into the bounds of the background before it appears.
- if (goingToLauncherIconNotAligned) {
+ if (isInLauncherIconNotAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
- } else if (notGoingToLauncherIconNotAligned) {
+ } else if (notInLauncherIconNotAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
}
float newDuration = duration - startDelay;
- if (goingToLauncherIconIsAligned) {
+ if (isInLauncherIconIsAligned) {
// Make the background fade out faster so that it is gone by the time the
// icons move outside of the bounds of the background.
newDuration = duration * TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT;
@@ -373,7 +434,8 @@
animatorSet.play(taskbarBackgroundAlpha);
}
- float cornerRoundness = goingToLauncher ? 0 : 1;
+ float cornerRoundness = isInLauncher ? 0 : 1;
+
// Don't animate if corner roundness has reached desired value.
if (mTaskbarCornerRoundness.isAnimating()
|| mTaskbarCornerRoundness.value != cornerRoundness) {
@@ -412,8 +474,12 @@
return animatorSet;
}
- /** Returns whether we're going to a state where taskbar icons should align with launcher. */
- public boolean goingToAlignedLauncherState() {
+ /**
+ * Whether the taskbar is aligned with the hotseat in the current/target launcher state.
+ *
+ * This refers to the intended state - a transition to this state might be in progress.
+ */
+ public boolean isTaskbarAlignedWithHotseat() {
return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
}
@@ -481,8 +547,13 @@
}
}
+ /** Whether the launcher is considered active. */
private boolean isInLauncher() {
- return (mState & FLAGS_LAUNCHER) != 0;
+ if (hasAnyFlag(FLAG_SCREEN_ON)) {
+ return hasAnyFlag(FLAGS_LAUNCHER_ACTIVE);
+ } else {
+ return hasAnyFlag(FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF);
+ }
}
/**
@@ -509,7 +580,8 @@
if (firstFrameVisChanged && mCanSyncViews && !Utilities.isRunningInTestHarness()) {
ViewRootSync.synchronizeNextDraw(mLauncher.getHotseat(),
mControllers.taskbarActivityContext.getDragLayer(),
- () -> {});
+ () -> {
+ });
}
}
@@ -562,7 +634,7 @@
// Update the resumed state immediately to ensure a seamless handoff
boolean launcherResumed = !finishedToApp;
- updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+ updateStateForFlag(FLAG_TRANSITION_TO_RESUMED, false);
updateStateForFlag(FLAG_RESUMED, launcherResumed);
applyState();
@@ -576,17 +648,15 @@
}
private static String getStateString(int flags) {
- StringJoiner str = new StringJoiner("|");
- if ((flags & FLAG_RESUMED) != 0) {
- str.add("FLAG_RESUMED");
- }
- if ((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0) {
- str.add("FLAG_RECENTS_ANIMATION_RUNNING");
- }
- if ((flags & FLAG_TRANSITION_STATE_RUNNING) != 0) {
- str.add("FLAG_TRANSITION_STATE_RUNNING");
- }
- return str.toString();
+ StringJoiner result = new StringJoiner("|");
+ appendFlag(result, flags, FLAG_RESUMED, "resumed");
+ appendFlag(result, flags, FLAG_TRANSITION_TO_RESUMED, "transition_to_resumed");
+ appendFlag(result, flags, FLAG_LAUNCHER_IN_STATE_TRANSITION,
+ "launcher_in_state_transition");
+ appendFlag(result, flags, FLAG_SCREEN_ON, "screen_on");
+ appendFlag(result, flags, FLAG_LAUNCHER_ACTIVE_AT_SCREEN_OFF,
+ "launcher_active_at_screen_off");
+ return result.toString();
}
protected void dumpLogs(String prefix, PrintWriter pw) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 115b99e..0ed4538 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -65,6 +65,7 @@
/**
* Implements interfaces required to show and allow interacting with a PopupContainerWithArrow.
+ * Controls the long-press menu on Taskbar and AllApps icons.
*/
public class TaskbarPopupController implements TaskbarControllers.LoggableTaskbarController {
@@ -174,6 +175,7 @@
deepShortcutCount,
mPopupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
+ icon.clearAccessibilityFocus();
}
container.addOnAttachStateChangeListener(
@@ -190,9 +192,8 @@
// Make focusable to receive back events
context.onPopupVisibilityChanged(true);
- container.setOnCloseCallback(() -> {
+ container.addOnCloseCallback(() -> {
context.getDragLayer().post(() -> context.onPopupVisibilityChanged(false));
- container.setOnCloseCallback(null);
});
return container;
@@ -293,13 +294,19 @@
@Override
public void onClick(View view) {
+ // Add callbacks depending on what type of Taskbar context we're in (Taskbar or AllApps)
+ mTarget.onSplitScreenMenuButtonClicked();
AbstractFloatingView.closeAllOpenViews(mTarget);
+
+ // Depending on what app state we're in, we either want to initiate the split screen
+ // staging process or immediately launch a split with an existing app.
+ // - Initiate the split screen staging process
if (mAllowInitialSplitSelection) {
super.onClick(view);
return;
}
- // Initiate splitscreen from the in-app Taskbar or Taskbar All Apps
+ // - Immediately launch split with the running app
Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
LogUtils.getShellShareableInstanceId();
mTarget.getStatsLogManager().logger()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
new file mode 100644
index 0000000..d65b5c0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSpringOnStashController.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.anim.AnimatedFloat.VALUE;
+
+import android.animation.ValueAnimator;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController;
+import com.android.launcher3.util.DisplayController;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the spring animation when stashing the transient taskbar.
+ */
+public class TaskbarSpringOnStashController implements LoggableTaskbarController {
+
+ private final TaskbarActivityContext mContext;
+ private TaskbarControllers mControllers;
+ private final AnimatedFloat mTranslationForStash = new AnimatedFloat(
+ this::updateTranslationYForStash);
+
+ private final boolean mIsTransientTaskbar;
+
+ private final float mStartVelocityPxPerS;
+
+ public TaskbarSpringOnStashController(TaskbarActivityContext context) {
+ mContext = context;
+ mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext);
+ mStartVelocityPxPerS = context.getResources()
+ .getDimension(R.dimen.transient_taskbar_stash_spring_velocity_dp_per_s);
+ }
+
+ /**
+ * Initialization method.
+ */
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
+ private void updateTranslationYForStash() {
+ if (!mIsTransientTaskbar) {
+ return;
+ }
+
+ float transY = mTranslationForStash.value;
+ mControllers.stashedHandleViewController.setTranslationYForStash(transY);
+ mControllers.taskbarViewController.setTranslationYForStash(transY);
+ mControllers.taskbarDragLayerController.setTranslationYForStash(transY);
+ }
+
+ /**
+ * Returns a spring animation to be used when stashing the transient taskbar.
+ */
+ public @Nullable ValueAnimator createSpringToStash() {
+ if (!mIsTransientTaskbar) {
+ return null;
+ }
+ return new SpringAnimationBuilder(mContext)
+ .setStartValue(mTranslationForStash.value)
+ .setEndValue(0)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .setStartVelocity(mStartVelocityPxPerS)
+ .build(mTranslationForStash, VALUE);
+ }
+
+
+ @Override
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "TaskbarSpringOnStashController:");
+
+ pw.println(prefix + "\tmTranslationForStash=" + mTranslationForStash.value);
+ pw.println(prefix + "\tmStartVelocityPxPerS=" + mStartVelocityPxPerS);
+ }
+}
+
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index cbc1672..b613763 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -81,7 +81,7 @@
public static final int FLAG_IN_APP = 1 << 0;
public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted
- public static final int FLAG_STASHED_IN_SYSUI_STATE = 1 << 2; // app pinning, keyguard, etc.
+ public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 2; // shade open, ...
public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 3; // setup wizard and AllSetActivity
public static final int FLAG_STASHED_IN_APP_IME = 1 << 4; // IME is visible
public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
@@ -89,13 +89,14 @@
public static final int FLAG_IN_SETUP = 1 << 7; // In the Setup Wizard
public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 8; // phone screen gesture nav, stashed
public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 9; // Autohide (transient taskbar).
+ public static final int FLAG_STASHED_SYSUI = 1 << 10; // app pinning, keyguard, etc.
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
- | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_SETUP
+ | FLAG_STASHED_IN_APP_SYSUI | FLAG_STASHED_IN_APP_SETUP
| FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS
| FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
@@ -218,11 +219,11 @@
boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
- boolean stashedInTaskbarAllApps =
- hasAnyFlag(flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS);
- boolean stashedForSmallScreen = hasAnyFlag(flags, FLAG_STASHED_SMALL_SCREEN);
- return (inApp && stashedInApp) || (!inApp && stashedLauncherState)
- || stashedInTaskbarAllApps || stashedForSmallScreen;
+ boolean forceStashed = hasAnyFlag(flags,
+ FLAG_STASHED_SYSUI
+ | FLAG_STASHED_IN_TASKBAR_ALL_APPS
+ | FLAG_STASHED_SMALL_SCREEN);
+ return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed;
});
public TaskbarStashController(TaskbarActivityContext activity) {
@@ -712,6 +713,9 @@
play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay,
Math.max(0, duration - alphaStartDelay), LINEAR);
+ play(as, mControllers.taskbarSpringOnStashController.createSpringToStash(), 0, duration,
+ LINEAR);
+
if (skipStashAnimation) {
skipInterpolator = INSTANT;
}
@@ -898,13 +902,14 @@
long animDuration = TASKBAR_STASH_DURATION;
long startDelay = 0;
- updateStateForFlag(FLAG_STASHED_IN_SYSUI_STATE, hasAnyFlag(systemUiStateFlags,
+ updateStateForFlag(FLAG_STASHED_IN_APP_SYSUI, hasAnyFlag(systemUiStateFlags,
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+ | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED));
+ updateStateForFlag(FLAG_STASHED_SYSUI, hasAnyFlag(systemUiStateFlags,
SYSUI_STATE_SCREEN_PINNING
| SYSUI_STATE_BOUNCER_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
- | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
- | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
- | SYSUI_STATE_QUICK_SETTINGS_EXPANDED));
+ | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED));
// Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
@@ -1068,13 +1073,14 @@
StringJoiner sj = new StringJoiner("|");
appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
- appendFlag(sj, flags, FLAG_STASHED_IN_SYSUI_STATE, "FLAG_STASHED_IN_SYSUI_STATE");
+ appendFlag(sj, flags, FLAG_STASHED_IN_APP_SYSUI, "FLAG_STASHED_IN_APP_SYSUI");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE");
appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS");
appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP");
appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO");
+ appendFlag(sj, flags, FLAG_STASHED_SYSUI, "FLAG_STASHED_SYSUI");
return sj.toString();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 062b4ce..dd88a37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -138,7 +138,7 @@
* Returns an animation to reset the taskbar translation to {@code 0}.
*/
public ObjectAnimator createAnimToResetTranslation(long duration) {
- ObjectAnimator animator = ObjectAnimator.ofFloat(mTranslationYForSwipe, VALUE, 0);
+ ObjectAnimator animator = mTranslationYForSwipe.animateToValue(0);
animator.setInterpolator(Interpolators.LINEAR);
animator.setDuration(duration);
animator.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 4c6d3fa..8046cd6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -125,6 +125,12 @@
}
/**
+ * Screen state changed, see QuickStepContract.SCREEN_STATE_* values.
+ */
+ public void onChangeScreenState(int screenState){
+ }
+
+ /**
* Returns {@code true} iff taskbar is stashed.
*/
public boolean isTaskbarStashed() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 0116e16..c5b6cdf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -47,6 +47,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
import com.android.launcher3.views.IconButtonView;
@@ -66,6 +67,7 @@
private final int mIconTouchSize;
private final int mItemMarginLeftRight;
private final int mItemPadding;
+ private final int mFolderLeaveBehindColor;
private final boolean mIsRtl;
private final TaskbarActivityContext mActivityContext;
@@ -132,6 +134,9 @@
mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2;
mItemPadding = (mIconTouchSize - actualIconSize) / 2;
+ mFolderLeaveBehindColor = Themes.getAttrColor(mActivityContext,
+ android.R.attr.textColorTertiary);
+
// Needed to draw folder leave-behind when opening one.
setWillNotDraw(false);
@@ -523,7 +528,8 @@
if (mLeaveBehindFolderIcon != null) {
canvas.save();
canvas.translate(mLeaveBehindFolderIcon.getLeft(), mLeaveBehindFolderIcon.getTop());
- mLeaveBehindFolderIcon.getFolderBackground().drawLeaveBehind(canvas);
+ mLeaveBehindFolderIcon.getFolderBackground().drawLeaveBehind(canvas,
+ mFolderLeaveBehindColor);
canvas.restore();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4d92a9e..ad16eed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -103,6 +103,7 @@
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
private float mTaskbarIconTranslationYForSwipe;
+ private float mTaskbarIconTranslationYForSpringOnStash;
private final int mTaskbarBottomMargin;
private final int mStashedHandleHeight;
@@ -291,10 +292,19 @@
updateTranslationY();
}
+ /**
+ * Sets the translation of the TaskbarView during the spring on stash animation.
+ */
+ public void setTranslationYForStash(float transY) {
+ mTaskbarIconTranslationYForSpringOnStash = transY;
+ updateTranslationY();
+ }
+
private void updateTranslationY() {
mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
+ mTaskbarIconTranslationYForStash.value
- + mTaskbarIconTranslationYForSwipe);
+ + mTaskbarIconTranslationYForSwipe
+ + mTaskbarIconTranslationYForSpringOnStash);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 3edb375..66d5918 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.taskbar.overlay;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-
import android.content.Context;
import android.view.View;
@@ -33,10 +31,6 @@
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
-import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.util.function.Consumer;
/**
* Window context for the taskbar overlays such as All Apps and EDU.
@@ -141,4 +135,8 @@
@Override
public void onPopupVisibilityChanged(boolean isVisible) {}
+
+ @Override
+ public void onSplitScreenMenuButtonClicked() {
+ }
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 4cca24e..172cb46 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -50,6 +50,7 @@
@Mock lateinit var voiceInteractionWindowController: VoiceInteractionWindowController
@Mock lateinit var taskbarRecentAppsController: TaskbarRecentAppsController
@Mock lateinit var taskbarTranslationController: TaskbarTranslationController
+ @Mock lateinit var taskbarSpringOnStashController: TaskbarSpringOnStashController
@Mock lateinit var taskbarOverlayController: TaskbarOverlayController
@Mock lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
@Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
@@ -89,6 +90,7 @@
taskbarInsetsController,
voiceInteractionWindowController,
taskbarTranslationController,
+ taskbarSpringOnStashController,
taskbarRecentAppsController,
taskbarEduTooltipController,
keyboardQuickSwitchController
diff --git a/res/layout/widgets_full_sheet_large_screen.xml b/res/layout/widgets_full_sheet_large_screen.xml
index b99ac5c..808d3eb 100644
--- a/res/layout/widgets_full_sheet_large_screen.xml
+++ b/res/layout/widgets_full_sheet_large_screen.xml
@@ -20,68 +20,89 @@
android:orientation="vertical"
android:theme="?attr/widgetsTheme">
- <androidx.constraintlayout.widget.ConstraintLayout
+ <com.android.launcher3.views.SpringRelativeLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:importantForAccessibility="no">
- <FrameLayout
- android:id="@+id/recycler_view_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/title"
- app:layout_constraintWidth_percent="0.33">
+ <View
+ android:id="@+id/collapse_handle"
+ android:layout_width="@dimen/bottom_sheet_handle_width"
+ android:layout_height="@dimen/bottom_sheet_handle_height"
+ android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
+ android:layout_centerHorizontal="true"
+ android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"/>
- <TextView
- android:id="@+id/fast_scroller_popup"
- style="@style/FastScrollerPopup"
- android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:gravity="center_horizontal"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:text="@string/widget_button_text"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="24sp" />
- <!-- Fast scroller popup -->
- <com.android.launcher3.views.RecyclerViewFastScroller
- android:id="@+id/fast_scroller"
- android:layout_width="@dimen/fastscroll_width"
+ <LinearLayout
+ android:id="@+id/linear_layout_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/title">
+
+ <FrameLayout
+ android:id="@+id/recycler_view_container"
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+ android:layout_gravity="start"
+ android:layout_weight="0.33">
+ <TextView
+ android:id="@+id/fast_scroller_popup"
+ style="@style/FastScrollerPopup"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
- <com.android.launcher3.widget.picker.WidgetsRecyclerView
- android:id="@+id/search_widgets_list_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipToPadding="false"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
- android:visibility="gone" />
- </FrameLayout>
+ <!-- Fast scroller popup -->
+ <com.android.launcher3.views.RecyclerViewFastScroller
+ android:id="@+id/fast_scroller"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/fastscroll_end_margin" />
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@id/recycler_view_container"
- app:layout_constraintTop_toBottomOf="@id/title"
- android:paddingEnd="16dp"
- android:paddingStart="8dp"
- android:layout_marginTop="26dp"
- app:layout_constraintWidth_percent="0.67"
- app:layout_constraintBottom_toBottomOf="parent"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/no_widgets_text"
- style="@style/PrimaryHeadline"
- android:layout_width="match_parent"
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/search_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/right_pane_container"
+ android:layout_width="0dp"
android:layout_height="match_parent"
- android:gravity="center"
- android:textSize="18sp"
- android:visibility="gone"
- tools:text="No widgets available" />
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/right_pane">
+ android:layout_weight="0.67"
+ android:paddingEnd="16dp"
+ android:paddingTop="24dp"
+ android:gravity="end"
+ android:layout_gravity="end"
+ android:paddingStart="8dp"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/no_widgets_text"
+ style="@style/PrimaryHeadline"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textSize="18sp"
+ android:visibility="gone"
+ tools:text="No widgets available" />
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/right_pane">
<com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
android:id="@+id/recommended_widget_table"
android:background="@drawable/widgets_surface_background"
@@ -91,32 +112,8 @@
"@dimen/widget_list_horizontal_margin_large_screen"
android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
android:visibility="gone" />
- </ScrollView>
- </FrameLayout>
-
- <View
- android:id="@+id/collapse_handle"
- android:layout_width="@dimen/bottom_sheet_handle_width"
- android:layout_height="@dimen/bottom_sheet_handle_height"
- android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
- android:background="@drawable/bg_rounded_corner_bottom_sheet_handle"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/collapse_handle"
- android:layout_marginTop="24dp"
- android:gravity="center_horizontal"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_large_screen"
- android:text="@string/widget_button_text"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="24sp" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </ScrollView>
+ </FrameLayout>
+ </LinearLayout>
+ </com.android.launcher3.views.SpringRelativeLayout>
</com.android.launcher3.widget.picker.WidgetsFullSheet>
diff --git a/res/layout/widgets_full_sheet_paged_view_large_screen.xml b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
index edee352..f729981 100644
--- a/res/layout/widgets_full_sheet_paged_view_large_screen.xml
+++ b/res/layout/widgets_full_sheet_paged_view_large_screen.xml
@@ -18,13 +18,11 @@
<FrameLayout
android:id="@+id/widgets_full_sheet_paged_view_large_screen"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintEnd_toStartOf="@id/scrollView"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/title"
- app:layout_constraintWidth_percent="0.33">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="start"
+ android:layout_gravity="start"
+ android:layout_alignParentStart="true">
<com.android.launcher3.widget.picker.WidgetPagedView
android:id="@+id/widgets_view_pager"
android:layout_width="match_parent"
diff --git a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
index c6a4f62..8fef303 100644
--- a/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
+++ b/res/layout/widgets_full_sheet_recyclerview_large_screen.xml
@@ -18,13 +18,11 @@
<FrameLayout
android:id="@+id/widgets_full_sheet_recyclerview_large_screen"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintEnd_toStartOf="@id/scrollView"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/title"
- app:layout_constraintWidth_percent="0.33">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="start"
+ android:layout_gravity="start"
+ android:layout_alignParentStart="true">
<com.android.launcher3.widget.picker.WidgetsRecyclerView
android:id="@+id/primary_widgets_list_view"
@@ -65,4 +63,4 @@
</LinearLayout>
</com.android.launcher3.views.StickyHeaderLayout>
</FrameLayout>
-</merge>
+</merge>
\ No newline at end of file
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 38b0e08..3bda94b 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -92,6 +92,9 @@
private static final String TAG = "CellLayout";
private static final boolean LOGD = false;
+ /** The color of the "leave-behind" shape when a folder is opened from Hotseat. */
+ private static final int FOLDER_LEAVE_BEHIND_COLOR = Color.argb(160, 245, 245, 245);
+
protected final ActivityContext mActivity;
@ViewDebug.ExportedProperty(category = "launcher")
@Thunk int mCellWidth;
@@ -100,7 +103,7 @@
private int mFixedCellWidth;
private int mFixedCellHeight;
@ViewDebug.ExportedProperty(category = "launcher")
- private Point mBorderSpace;
+ protected Point mBorderSpace;
@ViewDebug.ExportedProperty(category = "launcher")
protected int mCountX;
@@ -528,7 +531,7 @@
mFolderLeaveBehind.mDelegateCellY, mTempLocation);
canvas.save();
canvas.translate(mTempLocation[0], mTempLocation[1]);
- mFolderLeaveBehind.drawLeaveBehind(canvas);
+ mFolderLeaveBehind.drawLeaveBehind(canvas, FOLDER_LEAVE_BEHIND_COLOR);
canvas.restore();
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index c81ad01..abf5866 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -31,7 +31,11 @@
import android.content.pm.LauncherApps;
import android.os.UserHandle;
import android.util.Log;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.config.FeatureFlags;
@@ -70,6 +74,12 @@
private final InvariantDeviceProfile mInvariantDeviceProfile;
private final RunnableList mOnTerminateCallback = new RunnableList();
+ // WORKAROUND: b/269335387 remove this after widget background listener is enabled
+ /* Array of RemoteViews cached by Launcher process */
+ @GuardedBy("itself")
+ @NonNull
+ public final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
+
public static LauncherAppState getInstance(final Context context) {
return INSTANCE.get(context);
}
diff --git a/src/com/android/launcher3/MultipageCellLayout.java b/src/com/android/launcher3/MultipageCellLayout.java
index 12cb35d..20e9f60 100644
--- a/src/com/android/launcher3/MultipageCellLayout.java
+++ b/src/com/android/launcher3/MultipageCellLayout.java
@@ -95,6 +95,13 @@
}
@Override
+ public int getUnusedHorizontalSpace() {
+ return (int) Math.ceil(
+ (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth)
+ - ((mCountX - 1) * mBorderSpace.x)) / 2f);
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
if (mLeftBackground.getAlpha() > 0) {
mLeftBackground.setState(mBackground.getState());
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 3c316b8..27119ae 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -174,7 +174,7 @@
mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false);
popup.requestFocus();
- popup.setOnCloseCallback(() -> {
+ popup.addOnCloseCallback(() -> {
host.requestFocus();
host.sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 38f33de..43f2329 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -351,7 +351,7 @@
"SHOW_DOT_PAGINATION", true, "Enable showing dot pagination in workspace");
public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(270395809,
- "LARGE_SCREEN_WIDGET_PICKER", false, "Enable new widget picker that takes "
+ "LARGE_SCREEN_WIDGET_PICKER", true, "Enable new widget picker that takes "
+ "advantage of large screen format");
public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 8f9fa8a..2465745 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -333,12 +333,15 @@
getOffsetX() + inset, getOffsetY() + inset, getScaledRadius() - inset, mPaint);
}
- public void drawLeaveBehind(Canvas canvas) {
+ /**
+ * Draws the leave-behind circle on the given canvas and in the given color.
+ */
+ public void drawLeaveBehind(Canvas canvas, int color) {
float originalScale = mScale;
mScale = 0.5f;
mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(Color.argb(160, 245, 245, 245));
+ mPaint.setColor(color);
getShape().drawShape(canvas, getOffsetX(), getOffsetY(), getScaledRadius(), mPaint);
mScale = originalScale;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index be3a09b..9d06d4a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -48,14 +48,13 @@
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
@@ -124,7 +123,7 @@
private final GradientDrawable mRoundedTop;
private final GradientDrawable mRoundedBottom;
- @Nullable private Runnable mOnCloseCallback = null;
+ private RunnableList mOnCloseCallbacks = new RunnableList();
// The rect string of the view that the arrow is attached to, in screen reference frame.
protected int mArrowColor;
@@ -785,16 +784,14 @@
mDeferContainerRemoval = false;
getPopupContainer().removeView(this);
getPopupContainer().removeView(mArrow);
- if (mOnCloseCallback != null) {
- mOnCloseCallback.run();
- }
+ mOnCloseCallbacks.executeAllAndClear();
}
/**
- * Callback to be called when the popup is closed
+ * Callbacks to be called when the popup is closed
*/
- public void setOnCloseCallback(@Nullable Runnable callback) {
- mOnCloseCallback = callback;
+ public void addOnCloseCallback(Runnable callback) {
+ mOnCloseCallbacks.add(callback);
}
protected BaseDragLayer getPopupContainer() {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 0b756b6..e62ccbc 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -16,6 +16,7 @@
package com.android.launcher3.testing;
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
+import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.annotation.TargetApi;
@@ -156,7 +157,7 @@
case TestProtocol.REQUEST_IS_TWO_PANELS:
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- mDeviceProfile.isTwoPanels);
+ FOLDABLE_SINGLE_PAGE.get() ? false : mDeviceProfile.isTwoPanels);
return response;
case TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS:
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 8e67eb1..2ca825c 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -36,6 +36,7 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -74,8 +75,6 @@
private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
@NonNull
private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>();
- @NonNull
- private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
protected int mFlags = FLAG_STATE_IS_NORMAL;
@@ -174,6 +173,12 @@
public void deleteAppWidgetId(int appWidgetId) {
mWidgetHost.deleteAppWidgetId(appWidgetId);
mViews.remove(appWidgetId);
+ if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
+ final LauncherAppState state = LauncherAppState.getInstance(mContext);
+ synchronized (state.mCachedRemoteViews) {
+ state.mCachedRemoteViews.delete(appWidgetId);
+ }
+ }
}
/**
@@ -308,7 +313,17 @@
if (WidgetsModel.GO_DISABLE_WIDGETS) {
return;
}
-
+ if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
+ // Cache the content from the widgets when Launcher stops listening to widget updates
+ final LauncherAppState state = LauncherAppState.getInstance(mContext);
+ synchronized (state.mCachedRemoteViews) {
+ for (int i = 0; i < mViews.size(); i++) {
+ final int appWidgetId = mViews.keyAt(i);
+ final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
+ state.mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
+ }
+ }
+ }
mWidgetHost.stopListening();
setListeningFlag(false);
}
@@ -350,23 +365,24 @@
// RemoteViews from system process.
// TODO: have launcher always listens to widget updates in background so that this
// check can be removed altogether.
- if (FeatureFlags.ENABLE_CACHED_WIDGET.get()
- && mCachedRemoteViews.get(appWidgetId) != null) {
- // We've found RemoteViews from cache for this widget, so we will instantiate a
- // widget host view and populate it with the cached RemoteViews.
- final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
- view.setAppWidget(appWidgetId, appWidget);
- view.updateAppWidget(mCachedRemoteViews.get(appWidgetId));
- mDeferredViews.put(appWidgetId, view);
- mViews.put(appWidgetId, view);
- return view;
- } else {
- // When cache misses, a placeholder for the widget will be returned instead.
- DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
- view.setAppWidget(appWidgetId, appWidget);
- mViews.put(appWidgetId, view);
- return view;
+ if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
+ final RemoteViews cachedRemoteViews = getCachedRemoteViews(appWidgetId);
+ if (cachedRemoteViews != null) {
+ // We've found RemoteViews from cache for this widget, so we will instantiate a
+ // widget host view and populate it with the cached RemoteViews.
+ final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
+ view.setAppWidget(appWidgetId, appWidget);
+ view.updateAppWidget(cachedRemoteViews);
+ mDeferredViews.put(appWidgetId, view);
+ mViews.put(appWidgetId, view);
+ return view;
+ }
}
+ // If cache misses or not enabled, a placeholder for the widget will be returned.
+ DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
+ view.setAppWidget(appWidgetId, appWidget);
+ mViews.put(appWidgetId, view);
+ return view;
} else {
try {
return mWidgetHost.createView(context, appWidgetId, appWidget);
@@ -432,15 +448,8 @@
LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
tempHost.clearViews();
if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
- // First, we clear any previously cached content from existing widgets
- mCachedRemoteViews.clear();
+ // Clear previously cached content from existing widgets
mDeferredViews.clear();
- // Then we proceed to cache the content from the widgets
- for (int i = 0; i < mViews.size(); i++) {
- final int appWidgetId = mViews.keyAt(i);
- final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
- mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
- }
}
mViews.clear();
}
@@ -481,6 +490,14 @@
return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
}
+ @Nullable
+ private RemoteViews getCachedRemoteViews(int appWidgetId) {
+ final LauncherAppState state = LauncherAppState.getInstance(mContext);
+ synchronized (state.mCachedRemoteViews) {
+ return state.mCachedRemoteViews.get(appWidgetId);
+ }
+ }
+
/**
* Returns the new LauncherWidgetHolder instance
*/
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 0b2f5a5..d3be00c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -204,6 +204,7 @@
&& mDeviceProfile.isLandscape
&& LARGE_SCREEN_WIDGET_PICKER.get();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
+ mOrientation = Launcher.getLauncher(context).getOrientation();
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
@@ -232,13 +233,22 @@
mContent.setClipToOutline(true);
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
- int contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view
- : R.layout.widgets_full_sheet_recyclerview;
+
if (mIsTwoPane) {
- contentLayoutRes = mHasWorkProfile ? R.layout.widgets_full_sheet_paged_view_large_screen
- : R.layout.widgets_full_sheet_recyclerview_large_screen;
+ layoutInflater.inflate(
+ mHasWorkProfile
+ ? R.layout.widgets_full_sheet_paged_view_large_screen
+ : R.layout.widgets_full_sheet_recyclerview_large_screen,
+ findViewById(R.id.recycler_view_container),
+ true);
+ } else {
+ layoutInflater.inflate(
+ mHasWorkProfile
+ ? R.layout.widgets_full_sheet_paged_view
+ : R.layout.widgets_full_sheet_recyclerview,
+ mContent,
+ true);
}
- layoutInflater.inflate(contentLayoutRes, mContent, true);
mFastScroller = findViewById(R.id.fast_scroller);
if (mIsTwoPane) {
@@ -349,7 +359,8 @@
// if the current active page changes to personal or work we set suggestions
// to be the selected widget
- if (mIsTwoPane && (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB)) {
+ if (mIsTwoPane && mSuggestedWidgetsHeader != null
+ && (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB)) {
mSuggestedWidgetsHeader.callOnClick();
}
@@ -433,7 +444,9 @@
super.onAttachedToWindow();
mActivityContext.getAppWidgetHolder().addProviderChangeListener(this);
notifyWidgetProvidersChanged();
- onRecommendedWidgetsBound();
+ if (!mIsTwoPane) {
+ onRecommendedWidgetsBound();
+ }
}
@Override
@@ -696,6 +709,9 @@
recommendedWidgetsInTable, maxTableHeight);
} else {
mRecommendedWidgetsTable.setVisibility(GONE);
+ if (mSuggestedWidgetsContainer != null) {
+ mSuggestedWidgetsContainer.setVisibility(GONE);
+ }
}
}
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
index 1e6737d..2960807 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.celllayout;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+
import android.view.View;
import com.android.launcher3.CellLayout;
@@ -29,23 +31,31 @@
ArrayList<CellLayoutBoard> boards = new ArrayList<>();
int widgetCount = 0;
for (CellLayout cellLayout : launcher.getWorkspace().mWorkspaceScreens) {
- CellLayoutBoard board = new CellLayoutBoard();
+
int count = cellLayout.getShortcutsAndWidgets().getChildCount();
for (int i = 0; i < count; i++) {
View callView = cellLayout.getShortcutsAndWidgets().getChildAt(i);
CellLayoutLayoutParams params =
(CellLayoutLayoutParams) callView.getLayoutParams();
+
+ CellPosMapper.CellPos pos = launcher.getCellPosMapper().mapPresenterToModel(
+ params.getCellX(), params.getCellY(),
+ launcher.getWorkspace().getIdForScreen(cellLayout), CONTAINER_DESKTOP);
+ int screenId = pos.screenId;
+ if (screenId >= boards.size() - 1) {
+ boards.add(new CellLayoutBoard());
+ }
+ CellLayoutBoard board = boards.get(screenId);
// is icon
if (callView instanceof DoubleShadowBubbleTextView) {
- board.addIcon(params.getCellX(), params.getCellY());
+ board.addIcon(pos.cellX, pos.cellY);
} else {
// is widget
- board.addWidget(params.getCellX(), params.getCellY(), params.cellHSpan,
- params.cellVSpan, (char) ('A' + widgetCount));
+ board.addWidget(pos.cellX, pos.cellY, params.cellHSpan, params.cellVSpan,
+ (char) ('A' + widgetCount));
widgetCount++;
}
}
- boards.add(board);
}
return boards;
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 0fccf79..78a006e 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -60,11 +60,11 @@
final LauncherAppWidgetProviderInfo widgetInfo =
TestViewHelpers.findWidgetProvider(this, false /* hasConfigureScreen */);
- WidgetResizeFrame resizeFrame = mLauncher.
- getWorkspace().
- openAllWidgets().
- getWidget(widgetInfo.getLabel(mTargetContext.getPackageManager())).
- dragWidgetToWorkspace();
+ WidgetResizeFrame resizeFrame = mLauncher
+ .getWorkspace()
+ .openAllWidgets()
+ .getWidget(widgetInfo.getLabel(mTargetContext.getPackageManager()))
+ .dragWidgetToWorkspace();
assertTrue(mActivityMonitor.itemExists(
(info, view) -> info instanceof LauncherAppWidgetInfo &&
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 96e2e3f..c1c26ec 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -77,8 +77,8 @@
mLauncher.scroll(
widgetsContainer,
Direction.UP,
- new Rect(0, 0, mLauncher.getRightGestureMarginInContainer(widgetsContainer) + 1,
- 0),
+ new Rect(0, 0, 0,
+ mLauncher.getBottomGestureMarginInContainer(widgetsContainer) + 1),
FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
@@ -168,6 +168,8 @@
private UiObject2 findTestAppWidgetsTableContainer() {
final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
"widgets_list_header");
+ final BySelector widgetPickerSelector = By.res(mLauncher.getLauncherPackageName(),
+ "container");
final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
mLauncher.getContext().getPackageName());
final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(),
@@ -176,17 +178,23 @@
boolean hasHeaderExpanded = false;
int scrollDistance = 0;
for (int i = 0; i < SCROLL_ATTEMPTS; i++) {
- UiObject2 fullWidgetsPicker = verifyActiveContainer();
-
- UiObject2 header = mLauncher.waitForObjectInContainer(fullWidgetsPicker,
+ UiObject2 widgetPicker = mLauncher.waitForLauncherObject(widgetPickerSelector);
+ UiObject2 widgetListView = verifyActiveContainer();
+ UiObject2 header = mLauncher.waitForObjectInContainer(widgetListView,
headerSelector);
+ // If we are in a tablet in landscape mode then we will have a two pane view and we use
+ // the right pane to display the widgets table.
+ UiObject2 rightPane = mLauncher.findObjectInContainer(
+ widgetPicker,
+ widgetsContainerSelector);
+
// If a header is barely visible in the bottom edge of the screen, its height could be
// too small for a scroll gesture. Since all header should have roughly the same height,
// let's pick the max height we have seen so far.
scrollDistance = Math.max(scrollDistance, header.getVisibleBounds().height());
// Look for a header that has the test app name.
- UiObject2 headerTitle = mLauncher.findObjectInContainer(fullWidgetsPicker,
+ UiObject2 headerTitle = mLauncher.findObjectInContainer(widgetListView,
targetAppSelector);
if (headerTitle != null) {
// If we find the header and it has not been expanded, let's click it to see the
@@ -202,7 +210,8 @@
}
// Look for a widgets list.
- UiObject2 widgetsContainer = mLauncher.findObjectInContainer(fullWidgetsPicker,
+ UiObject2 widgetsContainer = mLauncher.findObjectInContainer(
+ rightPane != null ? rightPane : widgetListView,
widgetsContainerSelector);
if (widgetsContainer != null) {
log("Widgets container found.");
@@ -210,7 +219,9 @@
}
}
log("Finding test widget package - scroll with distance: " + scrollDistance);
- mLauncher.scrollDownByDistance(fullWidgetsPicker, scrollDistance);
+ mLauncher.scrollDownByDistance(hasHeaderExpanded && rightPane != null
+ ? rightPane
+ : widgetListView, scrollDistance);
}
return null;