Merge "Close system dialogs on Taskbar home button tap" into tm-qpr-dev
diff --git a/quickstep/res/values-sw600dp/config.xml b/quickstep/res/values-sw600dp/config.xml
deleted file mode 100644
index e1e442f..0000000
--- a/quickstep/res/values-sw600dp/config.xml
+++ /dev/null
@@ -1,21 +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.
--->
-<!-- Applies to large tablet screens portrait -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">true</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp-land/config.xml b/quickstep/res/values-sw720dp-land/config.xml
deleted file mode 100644
index bf0f9ad..0000000
--- a/quickstep/res/values-sw720dp-land/config.xml
+++ /dev/null
@@ -1,21 +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.
--->
-<!-- Applies to large tablet screens landscape -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">false</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-sw720dp/config.xml b/quickstep/res/values-sw720dp/config.xml
deleted file mode 100644
index e1e442f..0000000
--- a/quickstep/res/values-sw720dp/config.xml
+++ /dev/null
@@ -1,21 +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.
--->
-<!-- Applies to large tablet screens portrait -->
-<resources>
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">true</bool>
-</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 0d3aeb3..e45d9fd 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -52,10 +52,6 @@
<string name="setup_wizard_pkg" translatable="false" />
- <!-- Taskbar -->
- <!-- Align the Taskbar to the start (Left/Right) of the device when 3 button nav is enabled. -->
- <bool name="start_align_taskbar">false</bool>
-
<!-- This is a float because it is converted to dp later in DeviceProfile -->
<item name="taskbar_icon_size" type="dimen" format="float">44</item>
</resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 941b4b0..c4255bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -49,7 +49,8 @@
public static final int ALPHA_INDEX_STASHED = 0;
public static final int ALPHA_INDEX_HOME_DISABLED = 1;
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2;
- private static final int NUM_ALPHA_CHANNELS = 3;
+ public static final int ALPHA_INDEX_HIDDEN_WHILE_DREAMING = 3;
+ private static final int NUM_ALPHA_CHANNELS = 4;
/**
* The SharedPreferences key for whether the stashed handle region is dark.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 2628a7f..2fba37e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -53,6 +53,10 @@
// Translation property for taskbar background.
private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset);
+ // Used to fade in/out the entirety of the taskbar, for a smooth transition before/after sysui
+ // changes the inset visibility.
+ private final AnimatedFloat mTaskbarAlpha = new AnimatedFloat(this::updateTaskbarAlpha);
+
// Initialized in init.
private TaskbarControllers mControllers;
private TaskbarStashViaTouchController mTaskbarStashViaTouchController;
@@ -83,6 +87,9 @@
mAssistantBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
+
+ mTaskbarAlpha.value = 1;
+ updateTaskbarAlpha();
}
public void onDestroy() {
@@ -127,6 +134,10 @@
return mBgOffset;
}
+ public AnimatedFloat getTaskbarAlpha() {
+ return mTaskbarAlpha;
+ }
+
/**
* Make updates when configuration changes.
*/
@@ -165,6 +176,10 @@
updateOnBackgroundNavButtonColorIntensity();
}
+ private void updateTaskbarAlpha() {
+ mTaskbarDragLayer.setAlpha(mTaskbarAlpha.value);
+ }
+
@Override
public void setCornerRoundness(float cornerRoundness) {
mTaskbarDragLayer.setCornerRoundness(cornerRoundness);
@@ -188,6 +203,7 @@
pw.println(prefix + "TaskbarDragLayerController:");
pw.println(prefix + "\tmBgOffset=" + mBgOffset.value);
+ pw.println(prefix + "\tmTaskbarAlpha=" + mTaskbarAlpha.value);
pw.println(prefix + "\tmFolderMargin=" + mFolderMargin);
pw.println(prefix + "\tmLastSetBackgroundAlpha=" + mLastSetBackgroundAlpha);
pw.println(prefix + "\t\tmBgOverride=" + mBgOverride.value);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index b98ea81..58cb558 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -23,11 +23,15 @@
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_AWAKE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
+import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -93,9 +97,25 @@
*/
private static final int FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE = 1 << 4;
- /** Whether the device is currently locked. */
+ /**
+ * Whether the device is currently locked.
+ * <ul>
+ * <li>While locked, the taskbar is always stashed.<li/>
+ * <li>Navbar animations on FLAG_DEVICE_LOCKED transitions will get special treatment.</li>
+ * </ul>
+ */
private static final int FLAG_DEVICE_LOCKED = 1 << 5;
+ /**
+ * Whether the complete taskbar is completely hidden (neither visible stashed or unstashed).
+ * This is tracked to allow a nice transition of the taskbar before SysUI forces it away by
+ * hiding the inset.
+ *
+ * This flag is predominanlty set while FLAG_DEVICE_LOCKED is set, thus the taskbar's invisible
+ * resting state while hidden is stashed.
+ */
+ private static final int FLAG_TASKBAR_HIDDEN = 1 << 6;
+
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;
@@ -104,11 +124,21 @@
private static final float TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT = 0.33f;
private static final float TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT = 0.25f;
+ /**
+ * Delay for the taskbar fade-in.
+ *
+ * Helps to avoid visual noise when unlocking successfully via SFPS, and the device transitions
+ * to launcher directly. The delay avoids the navbar to become briefly visible. The duration
+ * is the same as in SysUI, see http://shortn/_uNSbDoRUSr.
+ */
+ private static final long TASKBAR_SHOW_DELAY_MS = 250;
+
private final AnimatedFloat mIconAlignment =
new AnimatedFloat(this::onIconAlignmentRatioChanged);
private TaskbarControllers mControllers;
private AnimatedFloat mTaskbarBackgroundAlpha;
+ private AnimatedFloat mTaskbarAlpha;
private AnimatedFloat mTaskbarCornerRoundness;
private MultiProperty mIconAlphaForHome;
private QuickstepLauncher mLauncher;
@@ -117,6 +147,9 @@
private int mState;
private LauncherState mLauncherState = LauncherState.NORMAL;
+ // Time when FLAG_TASKBAR_HIDDEN was last cleared, SystemClock.elapsedRealtime (milliseconds).
+ private long mLastUnlockTimeMs = 0;
+
private @Nullable TaskBarRecentsAnimationListener mTaskBarRecentsAnimationListener;
private boolean mIsAnimatingToLauncher;
@@ -187,6 +220,7 @@
mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
.getTaskbarBackgroundAlpha();
+ mTaskbarAlpha = mControllers.taskbarDragLayerController.getTaskbarAlpha();
mTaskbarCornerRoundness = mControllers.getTaskbarCornerRoundness();
mIconAlphaForHome = mControllers.taskbarViewController
.getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
@@ -279,6 +313,15 @@
boolean isDeviceLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
updateStateForFlag(FLAG_DEVICE_LOCKED, isDeviceLocked);
+ // Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
+ // interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
+ // when the device is asleep, the second condition extends ensures that the transition from
+ // and to the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar
+ // hide/reveal animation timings.
+ boolean isTaskbarHidden = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
+ || (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_AWAKE;
+ updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden);
+
if (skipAnim) {
applyState(0);
} else {
@@ -406,6 +449,41 @@
AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext);
}
+ if (hasAnyFlag(changedFlags, FLAG_TASKBAR_HIDDEN) && !hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
+ // Take note of the current time, as the taskbar is made visible again.
+ mLastUnlockTimeMs = SystemClock.elapsedRealtime();
+ }
+
+ boolean isHidden = hasAnyFlag(FLAG_TASKBAR_HIDDEN);
+ float taskbarAlpha = isHidden ? 0 : 1;
+ if (mTaskbarAlpha.isAnimating() || mTaskbarAlpha.value != taskbarAlpha) {
+ Animator taskbarVisibility = mTaskbarAlpha.animateToValue(taskbarAlpha);
+
+ taskbarVisibility.setDuration(duration);
+ if (isHidden) {
+ // Stash the transient taskbar once the taskbar is not visible. This reduces
+ // visual noise when unlocking the device afterwards.
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ TaskbarStashController stashController =
+ mControllers.taskbarStashController;
+ stashController.updateAndAnimateTransientTaskbar(
+ /* stash */ true, /* duration */ 0);
+ }
+ });
+ } else {
+ // delay the fade in animation a bit to reduce visual noise when waking up a device
+ // with a fingerprint reader. This should only be done when the device was woken
+ // up via fingerprint reader, however since this information is currently not
+ // available, opting to always delay the fade-in a bit.
+ long durationSinceLastUnlockMs = SystemClock.elapsedRealtime() - mLastUnlockTimeMs;
+ taskbarVisibility.setStartDelay(
+ Math.max(0, TASKBAR_SHOW_DELAY_MS - durationSinceLastUnlockMs));
+ }
+ animatorSet.play(taskbarVisibility);
+ }
+
float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
// Don't animate if background has reached desired value.
@@ -564,7 +642,7 @@
long resetDuration = mControllers.taskbarStashController.isInApp()
? duration
: duration / 2;
- if (!mControllers.taskbarTranslationController.willAnimateToZeroBefore(resetDuration)
+ if (mControllers.taskbarTranslationController.shouldResetBackToZero(resetDuration)
&& (isAnimatingToLauncher() || mLauncherState == LauncherState.NORMAL)) {
animatorSet.play(mControllers.taskbarTranslationController
.createAnimToResetTranslation(resetDuration));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c43b621..69ea9fd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -36,6 +36,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -43,6 +44,7 @@
import android.app.RemoteAction;
import android.content.SharedPreferences;
import android.graphics.drawable.Icon;
+import android.os.SystemClock;
import android.util.Log;
import android.view.InsetsController;
import android.view.View;
@@ -50,6 +52,7 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -68,6 +71,8 @@
import com.android.quickstep.SystemUiProxy;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.StringJoiner;
import java.util.function.IntPredicate;
@@ -184,6 +189,40 @@
// Auto stashes when user has not interacted with the Taskbar after X ms.
private static final long NO_TOUCH_TIMEOUT_TO_STASH_MS = 5000;
+ // Duration for which an unlock event is considered "current", as other events are received
+ // asynchronously.
+ private static final long UNLOCK_TRANSITION_MEMOIZATION_MS = 200;
+
+ /**
+ * The default stash animation, morphing the taskbar into the navbar.
+ */
+ private static final int TRANSITION_DEFAULT = 0;
+ /**
+ * Transitioning from launcher to app. Same as TRANSITION_DEFAULT, differs in internal
+ * animation timings.
+ */
+ private static final int TRANSITION_HOME_TO_APP = 1;
+ /**
+ * Fading the navbar in and out, where the taskbar jumpcuts in and out at the very begin/end of
+ * the transition. Used to transition between the hotseat and navbar` without the stash/unstash
+ * transition.
+ */
+ private static final int TRANSITION_HANDLE_FADE = 2;
+ /**
+ * Same as TRANSITION_DEFAULT, but exclusively used during an "navbar unstash to hotseat
+ * animation" bound to the progress of a swipe gesture. It differs from TRANSITION_DEFAULT
+ * by not scaling the height of the taskbar background.
+ */
+ private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ TRANSITION_DEFAULT,
+ TRANSITION_HOME_TO_APP,
+ TRANSITION_HANDLE_FADE,
+ TRANSITION_UNSTASH_SUW_MANUAL,
+ })
+ private @interface StashAnimation {}
+
private final TaskbarActivityContext mActivity;
private final SharedPreferences mPrefs;
private final int mStashedHeight;
@@ -472,9 +511,16 @@
}
/**
- * Stash or unstashes the transient taskbar.
+ * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
*/
public void updateAndAnimateTransientTaskbar(boolean stash) {
+ updateAndAnimateTransientTaskbar(stash, TASKBAR_STASH_DURATION);
+ }
+
+ /**
+ * Stash or unstashes the transient taskbar.
+ */
+ public void updateAndAnimateTransientTaskbar(boolean stash, long duration) {
if (!DisplayController.isTransientTaskbar(mActivity)) {
return;
}
@@ -553,8 +599,7 @@
createAnimToIsStashed(
/* isStashed= */ false,
placeholderDuration,
- /* animateBg= */ false,
- /* changedFlags=*/ 0);
+ TRANSITION_UNSTASH_SUW_MANUAL);
animation.play(mAnimator);
}
@@ -562,10 +607,15 @@
* 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 animateBg whether the taskbar's background should be animated
+ * @param animationType what transition type to play.
*/
- private void createAnimToIsStashed(boolean isStashed, long duration, boolean animateBg,
- int changedFlags) {
+ private void createAnimToIsStashed(boolean isStashed, long duration,
+ @StashAnimation int animationType) {
+ 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");
+ }
+
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -591,23 +641,10 @@
return;
}
- // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
- // already stashed Taskbar.
- boolean hotseatTopElement = mControllers.uiController.isHotseatIconOnTopWhenAligned()
- || !hasAnyFlag(changedFlags, FLAG_IN_APP);
- // If transitioning to unlocked device, do not play a stash animation.
- // Keep isUnlockTransition in sync with its counterpart in
- // TaskbarLauncherStateController#onStateChangeApplied.
- boolean isUnlockTransition = hasAnyFlag(changedFlags, FLAG_STASHED_DEVICE_LOCKED)
- && !hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
- boolean skipStashAnimation = !hotseatTopElement || isUnlockTransition;
-
if (isTransientTaskbar) {
- createTransientAnimToIsStashed(mAnimator, isStashed, duration, animateBg, changedFlags,
- skipStashAnimation);
+ createTransientAnimToIsStashed(mAnimator, isStashed, duration, animationType);
} else {
- createAnimToIsStashed(mAnimator, isStashed, duration, animateBg, skipStashAnimation,
- stashTranslation);
+ createAnimToIsStashed(mAnimator, isStashed, duration, stashTranslation, animationType);
}
mAnimator.addListener(new AnimatorListenerAdapter() {
@@ -636,7 +673,7 @@
}
private void createAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- boolean animateBg, boolean skipStashAnimation, float stashTranslation) {
+ float stashTranslation, @StashAnimation int animationType) {
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
@@ -650,12 +687,7 @@
secondHalfDurationScale = 0.5f;
fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation));
- if (animateBg) {
- fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1));
- } else {
- fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(1)));
- }
+ fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1));
firstHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(0),
@@ -666,7 +698,7 @@
mTaskbarStashedHandleAlpha.animateToValue(1)
);
- if (skipStashAnimation) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
fullLengthAnimatorSet.setInterpolator(INSTANT);
firstHalfAnimatorSet.setInterpolator(INSTANT);
}
@@ -677,6 +709,8 @@
fullLengthAnimatorSet.playTogether(
mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(0));
+
+ final boolean animateBg = animationType != TRANSITION_UNSTASH_SUW_MANUAL;
if (animateBg) {
fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(0));
} else {
@@ -691,7 +725,7 @@
mIconAlphaForStash.animateToValue(1)
);
- if (skipStashAnimation) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
fullLengthAnimatorSet.setInterpolator(FINAL_FRAME);
secondHalfAnimatorSet.setInterpolator(FINAL_FRAME);
}
@@ -714,61 +748,78 @@
}
private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- boolean animateBg, int changedFlags, boolean skipStashAnimation) {
- Interpolator skipInterpolator = null;
+ @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;
+ final float stashedHandleAlphaTarget = isStashed ? 1 : 0;
+
+ // Timing for the alpha values depend on the animation played
+ long iconAlphaStartDelay = 0, iconAlphaDuration = 0, stashedHandleAlphaDelay = 0,
+ stashedHandleAlphaDuration = 0;
+ if (duration > 0) {
+ if (animationType == TRANSITION_HANDLE_FADE) {
+ // When fading, the handle fades in/out at the beginning of the transition with
+ // TASKBAR_STASH_ALPHA_DURATION.
+ stashedHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ // The iconAlphaDuration must be set to duration for the skippable interpolators
+ // below to work.
+ iconAlphaDuration = duration;
+ } else {
+ iconAlphaStartDelay = TASKBAR_STASH_ALPHA_START_DELAY;
+ iconAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ stashedHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+
+ if (isStashed) {
+ if (animationType == TRANSITION_HOME_TO_APP) {
+ iconAlphaStartDelay = TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY;
+ }
+ stashedHandleAlphaDelay = iconAlphaStartDelay;
+ stashedHandleAlphaDuration = Math.max(0, duration - iconAlphaStartDelay);
+ }
+
+ }
+ }
+
+ play(as, mTaskbarStashedHandleAlpha.animateToValue(stashedHandleAlphaTarget),
+ stashedHandleAlphaDelay,
+ stashedHandleAlphaDuration, LINEAR);
+
+ // The rest of the animations might be "skipped" in TRANSITION_HANDLE_FADE transitions.
+ AnimatorSet skippable = as;
+ if (animationType == TRANSITION_HANDLE_FADE) {
+ skippable = new AnimatorSet();
+ as.play(skippable);
+ skippable.setInterpolator(isStashed ? INSTANT : FINAL_FRAME);
+ }
+
+ final boolean animateBg = animationType != TRANSITION_UNSTASH_SUW_MANUAL;
+ if (animateBg) {
+ play(skippable, mTaskbarBackgroundOffset.animateToValue(backgroundOffsetTarget), 0,
+ duration, EMPHASIZED);
+ } else {
+ skippable.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundOffset.updateValue(backgroundOffsetTarget)));
+ }
+
+ play(skippable, mIconAlphaForStash.animateToValue(iconAlphaTarget), iconAlphaStartDelay,
+ iconAlphaDuration,
+ LINEAR);
if (isStashed) {
- if (animateBg) {
- play(as, mTaskbarBackgroundOffset.animateToValue(1), 0, duration, EMPHASIZED);
- } else {
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(1)));
- }
-
- long alphaStartDelay = duration == 0 ? 0 : (changedFlags == FLAG_IN_APP)
- ? TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY
- : TASKBAR_STASH_ALPHA_START_DELAY;
- long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
- play(as, mIconAlphaForStash.animateToValue(0), alphaStartDelay, alphaDuration, LINEAR);
- play(as, mTaskbarStashedHandleAlpha.animateToValue(1), alphaStartDelay,
- Math.max(0, duration - alphaStartDelay), LINEAR);
-
- play(as, mControllers.taskbarSpringOnStashController.createSpringToStash(), 0, duration,
- LINEAR);
-
- if (skipStashAnimation) {
- skipInterpolator = INSTANT;
- }
- } else {
- if (animateBg) {
- play(as, mTaskbarBackgroundOffset.animateToValue(0), 0, duration, EMPHASIZED);
- } else {
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mTaskbarBackgroundOffset.updateValue(0)));
- }
-
- long alphaStartDelay = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_START_DELAY;
- long alphaDuration = duration == 0 ? 0 : TASKBAR_STASH_ALPHA_DURATION;
- play(as, mIconAlphaForStash.animateToValue(1), alphaStartDelay, alphaDuration, LINEAR);
- play(as, mTaskbarStashedHandleAlpha.animateToValue(0), 0, alphaDuration, LINEAR);
-
- if (skipStashAnimation) {
- skipInterpolator = FINAL_FRAME;
- }
+ play(skippable, mControllers.taskbarSpringOnStashController.createSpringToStash(),
+ 0, duration, LINEAR);
}
- mControllers.taskbarViewController.addRevealAnimToIsStashed(as, isStashed, duration,
+
+ mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
EMPHASIZED);
- if (skipInterpolator != null) {
- as.setInterpolator(skipInterpolator);
- }
-
- play(as, mControllers.stashedHandleViewController
+ play(skippable, mControllers.stashedHandleViewController
.createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
- as.play(mTaskbarStashedHandleHintScale.animateToValue(1f)
+ skippable.play(mTaskbarStashedHandleHintScale.animateToValue(1f)
.setDuration(isStashed ? duration / 2 : duration));
}
@@ -927,17 +978,10 @@
updateStateForFlag(FLAG_STASHED_SYSUI,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
- boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
- boolean wasLocked = hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
+ boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED)
+ && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY);
updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked);
- if (isLocked && !wasLocked && DisplayController.isTransientTaskbar(mActivity)) {
- // Stash the transient taskbar when locking the device. This improves the transition
- // to AoD (otherwise the taskbar stays a bit too long above the collapsing AoD scrim),
- // and ensures the taskar state is reset when unlocking the device afterwards.
- updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, true);
- }
-
// Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
@@ -1150,9 +1194,11 @@
private final IntPredicate mStashCondition;
private boolean mIsStashed;
- private boolean mIsHotseatIconOnTopWhenAligned;
+ private @StashAnimation int mLastStartedTransitionType = TRANSITION_DEFAULT;
private int mPrevFlags;
+ private long mLastUnlockTransitionTimeout = 0;
+
StatePropertyHolder(IntPredicate stashCondition) {
mStashCondition = stashCondition;
}
@@ -1170,7 +1216,7 @@
if (DEBUG) {
String stateString = formatFlagChange(flags, mPrevFlags,
- TaskbarStashController::getStateString);
+ TaskbarStashController::getStateString);
Log.d(TAG, "createSetStateAnimator: flags: " + stateString
+ ", duration: " + duration
+ ", isStashed: " + isStashed
@@ -1182,28 +1228,76 @@
onStateChangeApplied(changedFlags);
mPrevFlags = flags;
}
- boolean isHotseatIconOnTopWhenAligned =
- mControllers.uiController.isHotseatIconOnTopWhenAligned();
- // If an animation has started and mIsHotseatIconOnTopWhenAligned is changed, we need
- // to restart the animation with new parameters.
- if (mIsStashed != isStashed
- || (mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned
- && mAnimator != null && mAnimator.isStarted())) {
+
+ boolean isUnlockTransition = hasAnyFlag(changedFlags, FLAG_STASHED_DEVICE_LOCKED)
+ && !hasAnyFlag(FLAG_STASHED_DEVICE_LOCKED);
+ if (isUnlockTransition) {
+ // the launcher might not be resumed at the time the device is considered
+ // unlocked (when the keyguard goes away), but possibly shortly afterwards.
+ // To play the unlock transition at the time the unstash animation actually happens,
+ // this memoizes the state transition for UNLOCK_TRANSITION_MEMOIZATION_MS.
+ mLastUnlockTransitionTimeout =
+ SystemClock.elapsedRealtime() + UNLOCK_TRANSITION_MEMOIZATION_MS;
+ }
+
+ @StashAnimation int animationType = computeTransitionType(changedFlags);
+
+ // Allow re-starting animation if upgrading from default animation type, otherwise
+ // stick with the already started transition.
+ boolean transitionTypeChanged = mAnimator != null && mAnimator.isStarted()
+ && mLastStartedTransitionType == TRANSITION_DEFAULT
+ && animationType != TRANSITION_DEFAULT;
+
+ if (mIsStashed != isStashed || transitionTypeChanged) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.TASKBAR_IN_APP_STATE, String.format(
- "setState: mIsStashed=%b, isStashed=%b, duration=%d",
+ "setState: mIsStashed=%b, isStashed=%b, "
+ + "mAnimationType=%d, animationType=%d, duration=%d",
mIsStashed,
isStashed,
+ mLastStartedTransitionType,
+ animationType,
duration));
}
mIsStashed = isStashed;
- mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
+ mLastStartedTransitionType = animationType;
// This sets mAnimator.
- createAnimToIsStashed(mIsStashed, duration, /* animateBg= */ true, changedFlags);
+ createAnimToIsStashed(mIsStashed, duration, animationType);
return mAnimator;
}
return null;
}
+
+ private @StashAnimation int computeTransitionType(int changedFlags) {
+
+ boolean hotseatHiddenDuringAppLaunch =
+ !mControllers.uiController.isHotseatIconOnTopWhenAligned()
+ && hasAnyFlag(changedFlags, FLAG_IN_APP);
+ if (hotseatHiddenDuringAppLaunch) {
+ // When launching an app from the all-apps drawer, the hotseat is hidden behind the
+ // drawer. In this case, the navbar must just fade in, without a stash transition,
+ // as the taskbar stash animation would otherwise be visible above the all-apps
+ // drawer once the hotseat is detached.
+ return TRANSITION_HANDLE_FADE;
+ }
+
+ boolean isUnlockTransition =
+ SystemClock.elapsedRealtime() < mLastUnlockTransitionTimeout;
+ if (isUnlockTransition) {
+ // When transitioning to unlocked device, the hotseat will already be visible on
+ // the homescreen, thus do not play an un-stash animation.
+ // Keep isUnlockTransition in sync with its counterpart in
+ // TaskbarLauncherStateController#onStateChangeApplied.
+ return TRANSITION_HANDLE_FADE;
+ }
+
+ boolean homeToApp = hasAnyFlag(changedFlags, FLAG_IN_APP) && hasAnyFlag(FLAG_IN_APP);
+ if (homeToApp) {
+ return TRANSITION_HOME_TO_APP;
+ }
+
+ return TRANSITION_DEFAULT;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 065d111..4b18bb6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -54,6 +54,7 @@
private boolean mHasSprungOnceThisGesture;
private @Nullable ValueAnimator mSpringBounce;
private boolean mGestureEnded;
+ private boolean mGestureInProgress;
private boolean mAnimationToHomeRunning;
private final boolean mIsTransientTaskbar;
@@ -123,6 +124,7 @@
private void reset() {
mGestureEnded = false;
+ mGestureInProgress = false;
mHasSprungOnceThisGesture = false;
}
@@ -134,18 +136,24 @@
}
/**
- * Returns true if we will animate to zero before the input duration.
+ * Returns {@code true} if we should reset the animation back to zero.
+ *
+ * Returns {@code false} if there is a gesture in progress, or if we are already animating
+ * to 0 within the specified duration.
*/
- public boolean willAnimateToZeroBefore(long duration) {
+ public boolean shouldResetBackToZero(long duration) {
+ if (mGestureInProgress) {
+ return false;
+ }
if (mSpringBounce != null && mSpringBounce.isRunning()) {
long springDuration = mSpringBounce.getDuration();
long current = mSpringBounce.getCurrentPlayTime();
- return (springDuration - current < duration);
+ return (springDuration - current >= duration);
}
if (mTranslationYForSwipe.isAnimatingToValue(0)) {
- return mTranslationYForSwipe.getRemainingTime() < duration;
+ return mTranslationYForSwipe.getRemainingTime() >= duration;
}
- return false;
+ return true;
}
/**
@@ -188,6 +196,7 @@
mAnimationToHomeRunning = false;
cancelSpringIfExists();
reset();
+ mGestureInProgress = true;
}
/**
* Called when there is movement to move the taskbar.
@@ -211,6 +220,7 @@
mGestureEnded = true;
startSpring();
}
+ mGestureInProgress = false;
}
}
@@ -222,6 +232,7 @@
pw.println(prefix + "\tmHasSprungOnceThisGesture=" + mHasSprungOnceThisGesture);
pw.println(prefix + "\tmAnimationToHomeRunning=" + mAnimationToHomeRunning);
pw.println(prefix + "\tmGestureEnded=" + mGestureEnded);
+ pw.println(prefix + "\tmGestureInProgress=" + mGestureInProgress);
pw.println(prefix + "\tmSpringBounce is running=" + (mSpringBounce != null
&& mSpringBounce.isRunning()));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index b9242b2..1435cb0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -244,7 +244,8 @@
taskAttributes.getIconView().getDrawable(),
taskAttributes.getThumbnailView(),
taskAttributes.getThumbnailView().getThumbnail(),
- null /* intent */);
+ null /* intent */,
+ null /* user */);
return;
}
}
@@ -256,7 +257,8 @@
new BitmapDrawable(info.bitmap.icon),
startingView,
null /* thumbnail */,
- intent);
+ intent,
+ info.user);
}
);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 87df5b0..a3e6814 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -57,7 +57,8 @@
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
-public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable {
+public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
+ DeviceProfile.OnDeviceProfileChangeListener {
private static final String TAG = TaskbarView.class.getSimpleName();
private static final Rect sTmpRect = new Rect();
@@ -92,7 +93,7 @@
private float mTransientTaskbarAllAppsButtonTranslationXOffset;
- private final boolean mShouldTryStartAlign;
+ private boolean mShouldTryStartAlign;
public TaskbarView(@NonNull Context context) {
this(context, null);
@@ -121,8 +122,8 @@
resources.getDimension(isTransientTaskbar
? R.dimen.transient_taskbar_all_apps_button_translation_x_offset
: R.dimen.taskbar_all_apps_button_translation_x_offset);
- mShouldTryStartAlign = mActivityContext.isThreeButtonNav()
- && resources.getBoolean(R.bool.start_align_taskbar);
+
+ onDeviceProfileChanged(mActivityContext.getDeviceProfile());
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
@@ -162,6 +163,23 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mActivityContext.addOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivityContext.removeOnDeviceProfileChangeListener(this);
+ }
+
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ mShouldTryStartAlign = mActivityContext.isThreeButtonNav() && dp.startAlignTaskbar;
+ }
+
+ @Override
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) {
announceForAccessibility(mContext.getString(R.string.taskbar_a11y_shown_title));
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 1f4085f..5a883bf 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -88,11 +88,17 @@
private final StateManager mStateManager;
@Nullable
private DepthController mDepthController;
- private @StagePosition int mStagePosition;
+ private @StagePosition int mInitialStagePosition;
private ItemInfo mItemInfo;
+ /** {@link #mInitialTaskIntent} and {@link #mInitialUser} (the user of the Intent) are set
+ * together when split is initiated from an Intent. */
private Intent mInitialTaskIntent;
+ private UserHandle mInitialUser;
private int mInitialTaskId = INVALID_TASK_ID;
+ /** {@link #mSecondTaskIntent} and {@link #mSecondUser} (the user of the Intent) are set
+ * together when split is confirmed with an Intent. */
private Intent mSecondTaskIntent;
+ private UserHandle mSecondUser;
private int mSecondTaskId = INVALID_TASK_ID;
private boolean mRecentsAnimationRunning;
/** If {@code true}, animates the existing task view split placeholder view */
@@ -102,8 +108,6 @@
* split pair task view without wanting to animate current task dismissal overall
*/
private boolean mDismissingFromSplitPair;
- @Nullable
- private UserHandle mUser;
/** If not null, this is the TaskView we want to launch from */
@Nullable
private GroupedTaskView mLaunchingTaskView;
@@ -137,7 +141,7 @@
mInitialTaskId = alreadyRunningTask;
} else {
mInitialTaskIntent = intent;
- mUser = itemInfo.user;
+ mInitialUser = itemInfo.user;
}
setInitialData(stagePosition, splitEvent, itemInfo);
@@ -157,7 +161,7 @@
private void setInitialData(@StagePosition int stagePosition,
StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) {
mItemInfo = itemInfo;
- mStagePosition = stagePosition;
+ mInitialStagePosition = stagePosition;
mSplitEvent = splitEvent;
}
@@ -214,7 +218,7 @@
Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
LogUtils.getShellShareableInstanceId();
launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent,
- mStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
+ mInitialStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
instanceIds.first);
mStatsLogManager.logger()
@@ -231,8 +235,14 @@
mSecondTaskId = task.key.id;
}
- public void setSecondTask(Intent intent) {
+ /**
+ * To be called as soon as user selects the second app (even if animations aren't complete)
+ * @param intent The second intent that will be launched.
+ * @param user The user of that intent.
+ */
+ public void setSecondTask(Intent intent, UserHandle user) {
mSecondTaskIntent = intent;
+ mSecondUser = user;
}
/**
@@ -289,16 +299,17 @@
null /* options2 */, stagePosition, splitRatio, remoteTransition,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcut(intent1, options1, taskId2, stagePosition, splitRatio,
- remoteTransition, shellInstanceId);
+ launchIntentOrShortcut(intent1, mInitialUser, options1, taskId2, stagePosition,
+ splitRatio, remoteTransition, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcut(intent2, options1, taskId1,
+ launchIntentOrShortcut(intent2, mSecondUser, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
shellInstanceId);
} else {
- mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(),
- getPendingIntent(intent2), null /* options2 */, stagePosition,
- splitRatio, remoteTransition, shellInstanceId);
+ mSystemUiProxy.startIntents(getPendingIntent(intent1, mInitialUser),
+ options1.toBundle(), getPendingIntent(intent2, mSecondUser),
+ null /* options2 */, stagePosition, splitRatio, remoteTransition,
+ shellInstanceId);
}
} else {
final RemoteSplitLaunchAnimationRunner animationRunner =
@@ -312,60 +323,63 @@
taskId2, null /* options2 */, stagePosition, splitRatio, adapter,
shellInstanceId);
} else if (intent2 == null) {
- launchIntentOrShortcutLegacy(intent1, options1, taskId2, stagePosition, splitRatio,
- adapter, shellInstanceId);
+ launchIntentOrShortcutLegacy(intent1, mInitialUser, options1, taskId2,
+ stagePosition, splitRatio, adapter, shellInstanceId);
} else if (intent1 == null) {
- launchIntentOrShortcutLegacy(intent2, options1, taskId1,
+ launchIntentOrShortcutLegacy(intent2, mSecondUser, options1, taskId1,
getOppositeStagePosition(stagePosition), splitRatio, adapter,
shellInstanceId);
} else {
mSystemUiProxy.startIntentsWithLegacyTransition(
- getPendingIntent(intent1), getShortcutInfo(intent1), options1.toBundle(),
- getPendingIntent(intent2), getShortcutInfo(intent2), null /* options2 */,
- stagePosition, splitRatio, adapter, shellInstanceId);
+ getPendingIntent(intent1, mInitialUser),
+ getShortcutInfo(intent1, mInitialUser), options1.toBundle(),
+ getPendingIntent(intent2, mSecondUser),
+ getShortcutInfo(intent2, mSecondUser), null /* options2 */, stagePosition,
+ splitRatio, adapter, shellInstanceId);
}
}
}
- private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId,
- @StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition,
- @Nullable InstanceId shellInstanceId) {
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
+ private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
+ int taskId, @StagePosition int stagePosition, float splitRatio,
+ RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTask(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, remoteTransition, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTask(getPendingIntent(intent), options1.toBundle(), taskId,
- null /* options2 */, stagePosition, splitRatio, remoteTransition,
- shellInstanceId);
+ mSystemUiProxy.startIntentAndTask(getPendingIntent(intent, user),
+ options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
+ remoteTransition, shellInstanceId);
}
}
- private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId,
- @StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter,
+ private void launchIntentOrShortcutLegacy(Intent intent, UserHandle user,
+ ActivityOptions options1, int taskId, @StagePosition int stagePosition,
+ float splitRatio, RemoteAnimationAdapter adapter,
@Nullable InstanceId shellInstanceId) {
- final ShortcutInfo shortcutInfo = getShortcutInfo(intent);
+ final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
if (shortcutInfo != null) {
mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo,
options1.toBundle(), taskId, null /* options2 */, stagePosition,
splitRatio, adapter, shellInstanceId);
} else {
- mSystemUiProxy.startIntentAndTaskWithLegacyTransition(getPendingIntent(intent),
- options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
- adapter, shellInstanceId);
+ mSystemUiProxy.startIntentAndTaskWithLegacyTransition(
+ getPendingIntent(intent, user), options1.toBundle(), taskId,
+ null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId);
}
}
- private PendingIntent getPendingIntent(Intent intent) {
- return intent == null ? null : (mUser != null
+ private PendingIntent getPendingIntent(Intent intent, UserHandle user) {
+ return intent == null ? null : (user != null
? PendingIntent.getActivityAsUser(mContext, 0, intent,
- FLAG_MUTABLE, null /* options */, mUser)
+ FLAG_MUTABLE, null /* options */, user)
: PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE));
}
public @StagePosition int getActiveSplitStagePosition() {
- return mStagePosition;
+ return mInitialStagePosition;
}
public StatsLogManager.EventEnum getSplitEvent() {
@@ -377,7 +391,7 @@
}
@Nullable
- private ShortcutInfo getShortcutInfo(Intent intent) {
+ private ShortcutInfo getShortcutInfo(Intent intent, UserHandle user) {
if (intent == null || intent.getPackage() == null) {
return null;
}
@@ -389,7 +403,7 @@
try {
final Context context = mContext.createPackageContextAsUser(
- intent.getPackage(), 0 /* flags */, mUser);
+ intent.getPackage(), 0 /* flags */, user);
return new ShortcutInfo.Builder(context, shortcutId).build();
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage());
@@ -519,7 +533,9 @@
mInitialTaskIntent = null;
mSecondTaskId = INVALID_TASK_ID;
mSecondTaskIntent = null;
- mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
+ mInitialUser = null;
+ mSecondUser = null;
+ mInitialStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
mItemInfo = null;
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index e5c74dc..dd10c2d 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.os.UserHandle;
import android.view.View;
import com.android.launcher3.DeviceProfile;
@@ -66,21 +67,24 @@
}
Object tag = view.getTag();
Intent intent;
+ UserHandle user;
BitmapInfo bitmapInfo;
if (tag instanceof WorkspaceItemInfo) {
final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
intent = workspaceItemInfo.intent;
+ user = workspaceItemInfo.user;
bitmapInfo = workspaceItemInfo.bitmap;
} else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
final com.android.launcher3.model.data.AppInfo appInfo =
(com.android.launcher3.model.data.AppInfo) tag;
intent = appInfo.intent;
+ user = appInfo.user;
bitmapInfo = appInfo.bitmap;
} else {
return false;
}
- mController.setSecondTask(intent);
+ mController.setSecondTask(intent, user);
boolean isTablet = mLauncher.getDeviceProfile().isTablet;
SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6899f9e..904537f 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4575,11 +4575,13 @@
* is (either the ThumbnailView or the tapped icon).
* @param intent If we are launching a fresh instance of the app, this is the Intent for it. If
* the second app is already running in Recents, this will be null.
+ * @param user If we are launching a fresh instance of the app, this is the UserHandle for it.
+ * If the second app is already running in Recents, this will be null.
* @return true if waiting for confirmation of second app or if split animations are running,
* false otherwise
*/
public boolean confirmSplitSelect(TaskView containerTaskView, Task task, Drawable drawable,
- View secondView, @Nullable Bitmap thumbnail, Intent intent) {
+ View secondView, @Nullable Bitmap thumbnail, Intent intent, UserHandle user) {
if (canLaunchFullscreenTask()) {
return false;
}
@@ -4595,7 +4597,7 @@
}
mSplitSelectStateController.setSecondTask(task);
} else {
- mSplitSelectStateController.setSecondTask(intent);
+ mSplitSelectStateController.setSecondTask(intent, user);
}
RectF secondTaskStartingBounds = new RectF();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index df90583..42589ce 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -761,7 +761,8 @@
if (container != null) {
return getRecentsView().confirmSplitSelect(this, container.getTask(),
container.getIconView().getDrawable(), container.getThumbnailView(),
- container.getThumbnailView().getThumbnail(), /* intent */ null);
+ container.getThumbnailView().getThumbnail(), /* intent */ null,
+ /* user */ null);
}
return false;
}
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 7d6e83d..2dcde21 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -156,11 +156,11 @@
<string name="accessibility_close" msgid="2277148124685870734">"बन्द गर्नुहोस्"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"सूचना खारेज गरियो"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"व्यक्तिगत"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यसम्बन्धी"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"कामसम्बन्धी"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
<string name="work_profile_edu_work_apps" msgid="7895468576497746520">"कामसम्बन्धी एपहरूमा ब्याज अङ्कित हुन्छ र तपाईंका IT एड्मिन ती एप हेर्न सक्छन्"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"बुझेँ"</string>
- <string name="work_apps_paused_title" msgid="3040901117349444598">"कार्यसम्बन्धी एपहरू पज गरिएका छन्"</string>
+ <string name="work_apps_paused_title" msgid="3040901117349444598">"कामसम्बन्धी एपहरू पज गरिएका छन्"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"तपाईंका कामसम्बन्धी एपहरूले तपाईंलाई सूचना पठाउन, तपाईंको डिभाइसको ब्याट्री प्रयोग गर्न वा तपाईंको लोकेसन हेर्न सक्दैनन्"</string>
<string name="work_apps_paused_content_description" msgid="5149623040804051095">"कामसम्बन्धी एपहरू अफ गरिएका छन्। तपाईंका कामसम्बन्धी एपहरूले तपाईंलाई सूचना पठाउन, तपाईंको डिभाइसको ब्याट्री प्रयोग गर्न वा तपाईंको लोकेसन हेर्न सक्दैनन्"</string>
<string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"कामसम्बन्धी एपमा ब्याज अङ्कित हुन्छ र तपाईंका IT एड्मिन ती एप हेर्न सक्नुहुन्छ"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 682153f..417ae61 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -405,6 +405,16 @@
<!-- defaults to iconTextSize, if not specified -->
<attr name="iconTextSizeTwoPanelLandscape" format="float" />
+ <!-- If true, used to layout taskbar in 3 button navigation mode. -->
+ <!-- defaults to false if not specified -->
+ <attr name="startAlignTaskbar" format="boolean" />
+ <!-- defaults to startAlignTaskbar, if not specified -->
+ <attr name="startAlignTaskbarLandscape" format="boolean" />
+ <!-- defaults to startAlignTaskbarLandscape, if not specified -->
+ <attr name="startAlignTaskbarTwoPanelLandscape" format="boolean" />
+ <!-- defaults to startAlignTaskbar, if not specified -->
+ <attr name="startAlignTaskbarTwoPanelPortrait" format="boolean" />
+
<!-- If set, this display option is used to determine the default grid -->
<attr name="canBeDefault" format="boolean" />
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index fcb220e..86c9f16 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -267,6 +267,8 @@
public final int stashedTaskbarHeight;
public final int taskbarBottomMargin;
public final int taskbarIconSize;
+ // If true, used to layout taskbar in 3 button navigation mode.
+ public final boolean startAlignTaskbar;
// DragController
public int flingToDeleteThresholdVelocity;
@@ -338,12 +340,14 @@
res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_height);
taskbarBottomMargin =
res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+ startAlignTaskbar = false;
} else {
taskbarIconSize = pxFromDp(ResourcesCompat.getFloat(res, R.dimen.taskbar_icon_size),
mMetrics);
taskbarHeight = res.getDimensionPixelSize(R.dimen.taskbar_size);
stashedTaskbarHeight = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
taskbarBottomMargin = 0;
+ startAlignTaskbar = inv.startAlignTaskbar[mTypeIndex];
}
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 485b36c..4c34648 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -149,6 +149,8 @@
public float[] transientTaskbarIconSize;
+ public boolean[] startAlignTaskbar;
+
/**
* Number of icons inside the hotseat area.
*/
@@ -394,6 +396,8 @@
transientTaskbarIconSize = displayOption.transientTaskbarIconSize;
+ startAlignTaskbar = displayOption.startAlignTaskbar;
+
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, metrics);
@@ -915,6 +919,8 @@
private final float[] transientTaskbarIconSize = new float[COUNT_SIZES];
+ private final boolean[] startAlignTaskbar = new boolean[COUNT_SIZES];
+
DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
this.grid = grid;
@@ -1147,6 +1153,18 @@
R.styleable.ProfileDisplayOption_transientTaskbarIconSizeTwoPanelPortrait,
transientTaskbarIconSize[INDEX_DEFAULT]);
+ startAlignTaskbar[INDEX_DEFAULT] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbar, false);
+ startAlignTaskbar[INDEX_LANDSCAPE] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarLandscape,
+ startAlignTaskbar[INDEX_DEFAULT]);
+ startAlignTaskbar[INDEX_TWO_PANEL_LANDSCAPE] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarTwoPanelLandscape,
+ startAlignTaskbar[INDEX_LANDSCAPE]);
+ startAlignTaskbar[INDEX_TWO_PANEL_PORTRAIT] = a.getBoolean(
+ R.styleable.ProfileDisplayOption_startAlignTaskbarTwoPanelPortrait,
+ startAlignTaskbar[INDEX_DEFAULT]);
+
a.recycle();
}
@@ -1169,6 +1187,7 @@
allAppsIconTextSizes[i] = 0;
allAppsBorderSpaces[i] = new PointF();
transientTaskbarIconSize[i] = 0;
+ startAlignTaskbar[i] = false;
}
}
@@ -1213,6 +1232,7 @@
allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y;
transientTaskbarIconSize[i] += p.transientTaskbarIconSize[i];
+ startAlignTaskbar[i] |= p.startAlignTaskbar[i];
}
return this;
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index a5f33c0..c22cf40 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -153,6 +153,9 @@
isScalable = true
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = BooleanArray(4) { false }
+
inlineQsb = BooleanArray(4) { false }
devicePaddingId = R.xml.paddings_handhelds
@@ -233,6 +236,9 @@
isScalable = true
devicePaddingId = R.xml.paddings_6x5
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = booleanArrayOf(true, false, true, true)
+
inlineQsb = booleanArrayOf(false, true, false, false)
devicePaddingId = R.xml.paddings_handhelds
@@ -308,6 +314,9 @@
isScalable = true
+ transientTaskbarIconSize = FloatArray(4) { 44f }
+ startAlignTaskbar = BooleanArray(4) { true }
+
inlineQsb = booleanArrayOf(false, false, false, false)
devicePaddingId = R.xml.paddings_handhelds