Merge "Fix issue with global drag from taskbar being disabled" into tm-qpr-dev
diff --git a/quickstep/res/drawable/close_icon.xml b/quickstep/res/drawable/close_icon.xml
deleted file mode 100644
index 07f4336..0000000
--- a/quickstep/res/drawable/close_icon.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="#909090"
- android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
-</vector>
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 6d778ef..ff7c138 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -17,7 +17,6 @@
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.TaskbarStashController.TASKBAR_STASH_DURATION;
import android.animation.Animator;
@@ -93,7 +92,8 @@
}
private void animateToRecentsState(RecentsState toState) {
- Animator anim = createAnimToRecentsState(toState, TASKBAR_STASH_DURATION);
+ Animator anim = createAnimToRecentsState(toState,
+ mControllers.taskbarStashController.getStashDuration());
if (anim != null) {
anim.start();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 94d62b2..745defc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -425,7 +425,7 @@
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- return (mViewCallbacks != null && mViewCallbacks.onKeyUp(keyCode, event))
+ return (mViewCallbacks != null && mViewCallbacks.onKeyUp(keyCode, event, mIsRtl))
|| super.onKeyUp(keyCode, event);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index f0f361e..c1f764f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.view.KeyEvent;
+import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -125,18 +126,26 @@
}
private int launchTaskAt(int index) {
- KeyboardQuickSwitchTaskView taskView = mKeyboardQuickSwitchView.getTaskAt(index);
+ if (mCloseAnimation != null) {
+ // Ignore taps on task views and alt key unpresses while the close animation is running.
+ return -1;
+ }
+ // Even with a valid index, this can be null if the user tries to quick switch before the
+ // views have been added in the KeyboardQuickSwitchView.
+ View taskView = mKeyboardQuickSwitchView.getTaskAt(index);
GroupTask task = mControllerCallbacks.getTaskAt(index);
- if (taskView == null || task == null) {
+ if (task == null) {
return Math.max(0, index);
} else if (task.task2 == null) {
UI_HELPER_EXECUTOR.execute(() ->
ActivityManagerWrapper.getInstance().startActivityFromRecents(
task.task1.key,
mControllers.taskbarActivityContext.getActivityLaunchOptions(
- taskView, null).options));
+ taskView == null ? mKeyboardQuickSwitchView : taskView, null)
+ .options));
} else {
- mControllers.uiController.launchSplitTasks(taskView, task);
+ mControllers.uiController.launchSplitTasks(
+ taskView == null ? mKeyboardQuickSwitchView : taskView, task);
}
return -1;
}
@@ -160,15 +169,26 @@
class ViewCallbacks {
- boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode != KeyEvent.KEYCODE_TAB) {
+ boolean onKeyUp(int keyCode, KeyEvent event, boolean isRTL) {
+ if (keyCode != KeyEvent.KEYCODE_TAB
+ && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT
+ && keyCode != KeyEvent.KEYCODE_DPAD_LEFT
+ && keyCode != KeyEvent.KEYCODE_GRAVE
+ && keyCode != KeyEvent.KEYCODE_ESCAPE) {
return false;
}
+ if (keyCode == KeyEvent.KEYCODE_GRAVE || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ closeQuickSwitchView(true);
+ return true;
+ }
+ boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
+ || (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !isRTL)
+ || (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && isRTL);
int taskCount = mControllerCallbacks.getTaskCount();
int toIndex = mCurrentFocusIndex == -1
// Focus the second-most recent app if possible
? (taskCount > 1 ? 1 : 0)
- : (event.isShiftPressed()
+ : (traverseBackwards
// focus a more recent task or loop back to the opposite end
? Math.max(0, mCurrentFocusIndex == 0
? taskCount - 1 : mCurrentFocusIndex - 1)
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index ac584bf..3046076 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -388,12 +388,16 @@
}
@Override
- public void launchSplitTasks(View taskView, GroupTask groupTask) {
- super.launchSplitTasks(taskView, groupTask);
+ public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
mLauncher.launchSplitTasks(taskView, groupTask);
}
@Override
+ protected void onIconLayoutBoundsChanged() {
+ mTaskbarLauncherStateController.resetIconAlignment();
+ }
+
+ @Override
public void dumpLogs(String prefix, PrintWriter pw) {
super.dumpLogs(prefix, pw);
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 0f25ba1..f082fc6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -38,7 +38,6 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
-import com.android.systemui.shared.system.QuickStepContract;
import java.io.PrintWriter;
@@ -152,6 +151,14 @@
}
}
+ /**
+ * Returns the stashed handle bounds.
+ * @param out The destination rect.
+ */
+ public void getStashedHandleBounds(Rect out) {
+ out.set(mStashedHandleBounds);
+ }
+
private void initRegionSampler() {
mRegionSamplingHelper = new RegionSamplingHelper(mStashedHandleView,
new RegionSamplingHelper.SamplingCallback() {
@@ -194,16 +201,19 @@
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+ float startRadius = mStashedHandleRadius;
if (DisplayController.isTransientTaskbar(mActivity)) {
// Account for the full visual height of the transient taskbar.
int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
visualBounds.top -= heightDiff;
visualBounds.bottom += heightDiff;
+
+ startRadius = visualBounds.height() / 2f;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
- mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
+ startRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds);
boolean isReversed = !isStashed;
boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9b0f8c4..49dec1e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -560,8 +560,6 @@
public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
- mControllers.taskbarViewController.setImeIsVisible(
- mControllers.navbarButtonsViewController.isImeVisible());
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0, fromInit);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 82f27ae..c03c916 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -21,6 +21,7 @@
import android.graphics.Paint
import android.graphics.Path
import com.android.launcher3.R
+import com.android.launcher3.Utilities.mapRange
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.anim.Interpolators
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
@@ -51,6 +52,12 @@
private val invertedLeftCornerPath: Path = Path()
private val invertedRightCornerPath: Path = Path()
+ private val stashedHandleWidth =
+ context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width)
+
+ private val stashedHandleHeight =
+ context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height)
+
init {
paint.color = context.getColor(R.color.taskbar_background)
paint.flags = Paint.ANTI_ALIAS_FLAG
@@ -98,8 +105,8 @@
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
canvas.save()
- canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
if (!isTransientTaskbar || transientBackgroundBounds.isEmpty) {
+ canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
// Draw the background behind taskbar content.
canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
@@ -110,13 +117,21 @@
canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
canvas.drawPath(invertedRightCornerPath, paint)
} else {
- // Approximates the stash/unstash animation to transform the background.
- val scaleFactor = backgroundHeight / maxBackgroundHeight
- val width = transientBackgroundBounds.width()
- val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.2f, 1f, Interpolators.LINEAR)
- val newWidth = widthScale * width
- val delta = width - newWidth
- canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
+ // backgroundHeight is a value from [0...maxBackgroundHeight], so we can use it as a
+ // proxy to figure out the animation progress of the stash/unstash animation.
+ val progress = backgroundHeight / maxBackgroundHeight
+
+ // At progress 0, we draw the background as the stashed handle.
+ // At progress 1, we draw the background as the full taskbar.
+ val newBackgroundHeight =
+ mapRange(progress, stashedHandleHeight.toFloat(), maxBackgroundHeight)
+ val fullWidth = transientBackgroundBounds.width()
+ val newWidth = mapRange(progress, stashedHandleWidth.toFloat(), fullWidth.toFloat())
+ val halfWidthDelta = (fullWidth - newWidth) / 2f
+ val radius = newBackgroundHeight / 2f
+ val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
+
+ canvas.translate(0f, canvas.height - bottomMargin + bottomMarginProgress)
// Draw shadow.
val shadowAlpha =
@@ -128,20 +143,20 @@
setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
)
- // Draw background.
- val radius = backgroundHeight / 2f
+ // Aligns the bottom with the bottom of the stashed handle.
+ val bottom =
+ (-mapRange(1f - progress, 0f, stashedHandleHeight / 2f) + translationYForSwipe)
canvas.drawRoundRect(
- transientBackgroundBounds.left + (delta / 2f),
- translationYForSwipe,
- transientBackgroundBounds.right - (delta / 2f),
- backgroundHeight + translationYForSwipe,
+ transientBackgroundBounds.left + halfWidthDelta,
+ bottom - newBackgroundHeight,
+ transientBackgroundBounds.right - halfWidthDelta,
+ bottom,
radius,
radius,
paint
)
}
-
canvas.restore()
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 571d443..a6f59fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -84,7 +84,7 @@
windowLayoutParams.insetsRoundedCornerFrame = true
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
- gestureNavSettingsObserver.registerForCurrentUser()
+ gestureNavSettingsObserver.registerForCallingUser()
}
fun onDestroy() {
@@ -102,6 +102,7 @@
)
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ val res = context.resources;
for (provider in windowLayoutParams.providedInsets) {
if (
provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
@@ -113,7 +114,7 @@
} else if (provider.type == ITYPE_LEFT_GESTURES) {
provider.insetsSize =
Insets.of(
- gestureNavSettingsObserver.getLeftSensitivity(context.resources),
+ gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res),
0,
0,
0
@@ -123,7 +124,7 @@
Insets.of(
0,
0,
- gestureNavSettingsObserver.getRightSensitivity(context.resources),
+ gestureNavSettingsObserver.getRightSensitivityForCallingUser(res),
0
)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 9fd406d..0b86155 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -17,7 +17,6 @@
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.TaskbarStashController.TASKBAR_STASH_DURATION;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
import static com.android.systemui.animation.Interpolators.EMPHASIZED;
@@ -40,6 +39,7 @@
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
+import com.android.launcher3.util.window.RefreshRateTracker;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.views.RecentsView;
@@ -137,8 +137,7 @@
mIconAlphaForHome = mControllers.taskbarViewController
.getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
- mIconAlignment.finishAnimation();
- onIconAlignmentRatioChanged();
+ resetIconAlignment();
mLauncher.getStateManager().addStateListener(mStateListener);
@@ -232,7 +231,7 @@
}
public void applyState() {
- applyState(TASKBAR_STASH_DURATION);
+ applyState(mControllers.taskbarStashController.getStashDuration());
}
public void applyState(long duration) {
@@ -240,7 +239,7 @@
}
public Animator applyState(boolean start) {
- return applyState(TASKBAR_STASH_DURATION, start);
+ return applyState(mControllers.taskbarStashController.getStashDuration(), start);
}
public Animator applyState(long duration, boolean start) {
@@ -327,8 +326,17 @@
+ mTaskbarBackgroundAlpha.value
+ " -> " + backgroundAlpha + ": " + duration);
}
- animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(backgroundAlpha)
- .setDuration(duration));
+
+ Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha
+ .animateToValue(backgroundAlpha)
+ .setDuration(duration);
+ // Add a single frame delay to the taskbar bg to avoid too many moving parts during the
+ // app launch animation.
+ taskbarBackgroundAlpha.setStartDelay(
+ (hasAnyFlag(changedFlags, FLAG_RESUMED) && !goingToLauncher)
+ ? RefreshRateTracker.getSingleFrameMs(mLauncher)
+ : 0);
+ animatorSet.play(taskbarBackgroundAlpha);
}
float cornerRoundness = goingToLauncher ? 0 : 1;
@@ -431,6 +439,14 @@
return (mState & FLAGS_LAUNCHER) != 0;
}
+ /**
+ * Resets and updates the icon alignment.
+ */
+ protected void resetIconAlignment() {
+ mIconAlignment.finishAnimation();
+ onIconAlignmentRatioChanged();
+ }
+
private void onIconAlignmentRatioChanged() {
float currentValue = mIconAlphaForHome.getValue();
boolean taskbarWillBeVisible = mIconAlignment.value < 1;
@@ -452,6 +468,10 @@
}
private void updateIconAlphaForHome(float alpha) {
+ if (mControllers.taskbarActivityContext.isDestroyed()) {
+ Log.e("b/260135164", "updateIconAlphaForHome is called after Taskbar is destroyed",
+ new Exception());
+ }
mIconAlphaForHome.setValue(alpha);
boolean hotseatVisible = alpha == 0
|| (!mControllers.uiController.isHotseatIconOnTopWhenAligned()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 2f69b07..50f5d9e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -17,8 +17,10 @@
import static android.view.HapticFeedbackConstants.LONG_PRESS;
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
@@ -41,6 +43,7 @@
import android.view.InsetsController;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -101,11 +104,20 @@
/**
* How long to stash/unstash when manually invoked via long press.
+ *
+ * Use {@link #getStashDuration()} to query duration
*/
- public static final long TASKBAR_STASH_DURATION =
+ private static final long TASKBAR_STASH_DURATION =
InsetsController.ANIMATION_DURATION_RESIZE;
/**
+ * How long to stash/unstash transient taskbar.
+ *
+ * Use {@link #getStashDuration()} to query duration.
+ */
+ private static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
+
+ /**
* How long to stash/unstash when keyboard is appearing/disappearing.
*/
private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
@@ -113,7 +125,7 @@
/**
* The scale TaskbarView animates to when being stashed.
*/
- private static final float STASHED_TASKBAR_SCALE = 0.3f;
+ protected static final float STASHED_TASKBAR_SCALE = 0.5f;
/**
* How long the hint animation plays, starting on motion down.
@@ -122,6 +134,21 @@
ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
/**
+ * How long to delay the icon/stash handle alpha.
+ */
+ private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33;
+
+ /**
+ * How long the icon/stash handle alpha animation plays.
+ */
+ private static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+
+ /**
+ * How long to delay the icon/stash handle alpha for the home to app taskbar animation.
+ */
+ private static final long TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY = 66;
+
+ /**
* The scale that TaskbarView animates to when hinting towards the stashed state.
*/
private static final float STASHED_TASKBAR_HINT_SCALE = 0.9f;
@@ -299,7 +326,16 @@
boolean hideTaskbar = isVisible || !mActivity.isUserSetupComplete();
updateStateForFlag(FLAG_IN_SETUP, hideTaskbar);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, hideTaskbar);
- applyState(hideTaskbar ? 0 : TASKBAR_STASH_DURATION);
+ applyState(hideTaskbar ? 0 : getStashDuration());
+ }
+
+ /**
+ * Returns how long the stash/unstash animation should play.
+ */
+ public long getStashDuration() {
+ return DisplayController.isTransientTaskbar(mActivity)
+ ? TRANSIENT_TASKBAR_STASH_DURATION
+ : TASKBAR_STASH_DURATION;
}
/**
@@ -514,7 +550,10 @@
}
mAnimator = new AnimatorSet();
addJankMonitorListener(mAnimator, /* appearing= */ !mIsStashed);
- final float stashTranslation = isPhoneMode() ? 0 : (mUnstashedHeight - mStashedHeight);
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
+ final float stashTranslation = isPhoneMode() || isTransientTaskbar
+ ? 0
+ : (mUnstashedHeight - mStashedHeight);
if (!supportsVisualStashing()) {
// Just hide/show the icons and background instead of stashing into a handle.
@@ -522,8 +561,8 @@
.setDuration(duration));
mAnimator.playTogether(mTaskbarBackgroundOffset.animateToValue(isStashed ? 1 : 0)
.setDuration(duration));
- mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed ?
- stashTranslation : 0)
+ mAnimator.playTogether(mIconTranslationYForStash.animateToValue(isStashed
+ ? stashTranslation : 0)
.setDuration(duration));
mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
@@ -531,6 +570,40 @@
return;
}
+ // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
+ // already stashed Taskbar.
+ boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned()
+ && hasAnyFlag(changedFlags, FLAG_IN_APP);
+ if (isTransientTaskbar) {
+ createTransientAnimToIsStashed(mAnimator, isStashed, duration, animateBg, changedFlags,
+ skipStashAnimation);
+ } else {
+ createAnimToIsStashed(mAnimator, isStashed, duration, animateBg, skipStashAnimation,
+ stashTranslation);
+ }
+
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsStashed = isStashed;
+ onIsStashedChanged(mIsStashed);
+
+ cancelTimeoutIfExists();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+
+ if (!mIsStashed) {
+ tryStartTaskbarTimeout();
+ }
+ }
+ });
+ }
+
+ private void createAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
+ boolean animateBg, boolean skipStashAnimation, float stashTranslation) {
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
@@ -539,10 +612,6 @@
final float firstHalfDurationScale;
final float secondHalfDurationScale;
- // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
- // already stashed Taskbar.
- boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned()
- && hasAnyFlag(changedFlags, FLAG_IN_APP);
if (isStashed) {
firstHalfDurationScale = 0.75f;
secondHalfDurationScale = 0.5f;
@@ -595,10 +664,6 @@
}
}
- if (DisplayController.isTransientTaskbar(mActivity)) {
- fullLengthAnimatorSet.play(mControllers.taskbarViewController
- .createRevealAnimToIsStashed(isStashed));
- }
fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
.createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
@@ -610,26 +675,73 @@
secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
- mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
+ as.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
secondHalfAnimatorSet);
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIsStashed = isStashed;
- onIsStashedChanged(mIsStashed);
- cancelTimeoutIfExists();
+ }
+
+ private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
+ boolean animateBg, int changedFlags, boolean skipStashAnimation) {
+ Interpolator skipInterpolator = null;
+
+ if (isStashed) {
+ if (animateBg) {
+ play(as, mTaskbarBackgroundOffset.animateToValue(1), 0, duration, EMPHASIZED);
+ } else {
+ as.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundOffset.updateValue(1)));
}
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
+ 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);
- if (!mIsStashed) {
- tryStartTaskbarTimeout();
- }
+ 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(as, mControllers.taskbarViewController
+ .createRevealAnimToIsStashed(isStashed, isInApp()), 0, duration, EMPHASIZED);
+
+ if (skipInterpolator != null) {
+ as.setInterpolator(skipInterpolator);
+ }
+
+ play(as, 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)
+ .setDuration(isStashed ? duration / 2 : duration));
+ }
+
+ private static void play(AnimatorSet as, Animator a, long startDelay, long duration,
+ Interpolator interpolator) {
+ a.setDuration(duration);
+ a.setStartDelay(startDelay);
+ a.setInterpolator(interpolator);
+ as.play(a);
}
private void addJankMonitorListener(AnimatorSet animator, boolean expanding) {
@@ -711,7 +823,6 @@
}
}
-
/**
* Returns an animator which applies the latest state if mIsStashed is changed, or {@code null}
* otherwise.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 76b8b6d..24a089c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -25,6 +25,7 @@
import android.view.View;
import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.model.data.ItemInfo;
@@ -75,6 +76,11 @@
protected void onStashedInAppChanged() { }
+ /**
+ * Called when taskbar icon layout bounds change.
+ */
+ protected void onIconLayoutBoundsChanged() { }
+
/** Called when an icon is launched. */
@CallSuper
public void onTaskbarIconLaunched(ItemInfo item) {
@@ -248,15 +254,6 @@
}
/**
- * Closes the Keyboard Quick Switch View.
- *
- * No-op if the view is already closed
- */
- public void closeQuickSwitchView() {
- mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
- }
-
- /**
* Launches the focused task and closes the Keyboard Quick Switch View.
*
* If the overlay or view are closed, or the overview task is focused, then Overview is
@@ -275,5 +272,5 @@
*
* No-op if the view is not yet open.
*/
- public void launchSplitTasks(View taskview, GroupTask groupTask) { }
+ public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index eddc278..c1e85aa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -58,6 +58,8 @@
private static final String TAG = TaskbarView.class.getSimpleName();
private static final float TASKBAR_BACKGROUND_LUMINANCE = 0.30f;
+ private static final Rect sTmpRect = new Rect();
+
public int mThemeIconsBackground;
private final int[] mTempOutLocation = new int[2];
@@ -74,9 +76,6 @@
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
- // Prevents dispatching touches to children if true
- private boolean mTouchEnabled = true;
-
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
@@ -339,6 +338,9 @@
(right - navSpaceNeeded) - iconEnd;
iconEnd += offset;
}
+
+ sTmpRect.set(mIconLayoutBounds);
+
// Layout the children
mIconLayoutBounds.right = iconEnd;
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
@@ -379,14 +381,10 @@
mIconLayoutBounds.right = center + distanceFromCenter;
mIconLayoutBounds.left = center - distanceFromCenter;
}
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (!mTouchEnabled) {
- return true;
+ if (!sTmpRect.equals(mIconLayoutBounds)) {
+ mControllerCallbacks.notifyIconLayoutBoundsChanged();
}
- return super.dispatchTouchEvent(ev);
}
@Override
@@ -397,9 +395,6 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (!mTouchEnabled) {
- return true;
- }
if (mIconLayoutBounds.left <= event.getX()
&& event.getX() <= mIconLayoutBounds.right
&& !DisplayController.isTransientTaskbar(mActivityContext)) {
@@ -420,11 +415,6 @@
return super.onTouchEvent(event);
}
- public void setTouchesEnabled(boolean touchEnabled) {
- this.mTouchEnabled = touchEnabled;
- mControllerCallbacks.clearTouchInProgress();
- }
-
/**
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
* touch bounds.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 6252e60..c708838 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -17,9 +17,9 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.AnimatedFloat.VALUE;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
@@ -28,6 +28,7 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.graphics.Rect;
@@ -199,14 +200,6 @@
}
/**
- * Should be called when the IME visibility changes, so we can make Taskbar not steal touches.
- */
- public void setImeIsVisible(boolean isImeVisible) {
- mTaskbarView.setTouchesEnabled(!isImeVisible
- || DisplayController.isTransientTaskbar(mActivity));
- }
-
- /**
* Should be called when the recents button is disabled, so we can hide taskbar icons as well.
*/
public void setRecentsButtonDisabled(boolean isDisabled) {
@@ -310,13 +303,48 @@
* @param isStashed When true, the icon crops vertically to the size of the stashed handle.
* When false, the reverse happens.
*/
- public AnimatorSet createRevealAnimToIsStashed(boolean isStashed) {
+ public AnimatorSet createRevealAnimToIsStashed(boolean isStashed, boolean isInApp) {
AnimatorSet as = new AnimatorSet();
- for (int i = mTaskbarView.getChildCount() - 1; i >= 0; i--) {
+
+ Rect stashedBounds = new Rect();
+ mControllers.stashedHandleViewController.getStashedHandleBounds(stashedBounds);
+
+ int numChildren = mTaskbarView.getChildCount();
+ // We do not actually modify the width of the icons, but we will use this width to position
+ // the children to overlay the nav handle.
+ float virtualChildWidth = stashedBounds.width() / (float) numChildren;
+
+ for (int i = numChildren - 1; i >= 0; i--) {
View child = mTaskbarView.getChildAt(i);
- if (child instanceof BubbleTextView) {
- as.play(createRevealAnimForView(child, isStashed));
+
+ // Crop the icons to/from the nav handle shape.
+ as.play(createRevealAnimForView(child, isStashed));
+
+ // Translate the icons to/from their locations as the "nav handle."
+ // We look at 'left' and 'right' values to ensure that the children stay within the
+ // bounds of the stashed handle.
+ float iconLeft = child.getLeft();
+ float newLeft = stashedBounds.left + (virtualChildWidth * i);
+ final float croppedTransX;
+ if (iconLeft > newLeft) {
+ float newRight = stashedBounds.right - (virtualChildWidth * (numChildren - 1 - i));
+ croppedTransX = -(child.getLeft() + child.getWidth() - newRight);
+ } else {
+ croppedTransX = newLeft - iconLeft;
}
+
+ as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_X, isStashed
+ ? new float[] {croppedTransX}
+ : new float[] {croppedTransX, 0}));
+
+ float croppedTransY = child.getHeight() - stashedBounds.height();
+ as.play(ObjectAnimator.ofFloat(child, ICON_REVEAL_TRANSLATE_Y, isStashed
+ ? new float[] {croppedTransY}
+ : new float[] {croppedTransY, 0}));
+ as.addListener(forEndCallback(() -> {
+ ICON_REVEAL_TRANSLATE_X.set(child, 0f);
+ ICON_REVEAL_TRANSLATE_Y.set(child, 0f);
+ }));
}
return as;
}
@@ -409,7 +437,7 @@
float scale = ((float) taskbarDp.iconSizePx) / launcherDp.hotseatQsbVisualHeight;
setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator);
- setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
+ setter.setFloat(child, ICON_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
if (mIsHotseatIconOnTopWhenAligned) {
setter.addFloat(child, VIEW_ALPHA, 0f, 1f,
@@ -448,7 +476,7 @@
float childCenter = (child.getLeft() + child.getRight()) / 2f;
setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, interpolator);
- setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
+ setter.setFloat(child, ICON_TRANSLATE_Y, mTaskbarBottomMargin, interpolator);
setter.setFloat(child, SCALE_PROPERTY, scaleUp, interpolator);
}
@@ -626,6 +654,13 @@
public void clearTouchInProgress() {
mTouchInProgress = false;
}
+
+ /**
+ * Notifies launcher to update icon alignment.
+ */
+ public void notifyIconLayoutBoundsChanged() {
+ mControllers.uiController.onIconLayoutBoundsChanged();
+ }
}
public static final FloatProperty<View> ICON_TRANSLATE_X =
@@ -636,7 +671,7 @@
if (view instanceof BubbleTextView) {
((BubbleTextView) view).setTranslationXForTaskbarAlignmentAnimation(v);
} else if (view instanceof FolderIcon) {
- ((FolderIcon) view).setTranslationForTaskbarAlignmentAnimation(v);
+ ((FolderIcon) view).setTranslationXForTaskbarAlignmentAnimation(v);
} else {
view.setTranslationX(v);
}
@@ -653,4 +688,81 @@
return view.getTranslationX();
}
};
+
+ public static final FloatProperty<View> ICON_TRANSLATE_Y =
+ new FloatProperty<View>("taskbarAlignmentTranslateY") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationYForTaskbarAlignmentAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationYForTaskbarAlignmentAnimation(v);
+ } else {
+ view.setTranslationY(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view)
+ .getTranslationYForTaskbarAlignmentAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationYForTaskbarAlignmentAnimation();
+ }
+ return view.getTranslationY();
+ }
+ };
+
+ public static final FloatProperty<View> ICON_REVEAL_TRANSLATE_X =
+ new FloatProperty<View>("taskbarRevealTranslateX") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationXForTaskbarRevealAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationXForTaskbarRevealAnimation(v);
+ } else {
+ view.setTranslationX(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view).getTranslationXForTaskbarRevealAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationXForTaskbarRevealAnimation();
+ }
+ return view.getTranslationX();
+ }
+ };
+
+ public static final FloatProperty<View> ICON_REVEAL_TRANSLATE_Y =
+ new FloatProperty<View>("taskbarRevealTranslateY") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationYForTaskbarRevealAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationYForTaskbarRevealAnimation(v);
+ } else {
+ view.setTranslationY(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view).getTranslationYForTaskbarRevealAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationYForTaskbarRevealAnimation();
+ }
+ return view.getTranslationY();
+ }
+ };
+
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 80ce369..46cd045 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1214,7 +1214,7 @@
*
* If the second split task is missing, launches the first task normally.
*/
- public void launchSplitTasks(View taskView, GroupTask groupTask) {
+ public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
if (groupTask.task2 == null) {
UI_HELPER_EXECUTOR.execute(() ->
ActivityManagerWrapper.getInstance().startActivityFromRecents(
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index d0fd65f..ac5b2f2 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -37,6 +37,7 @@
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -185,6 +186,11 @@
&& dp != null
&& (dp.isTablet || dp.isTwoPanels);
+ if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+ // TODO(b/268075592): add support for quickswitch to/from desktop
+ allowQuickSwitch = false;
+ }
+
if (cmd.type == TYPE_HIDE) {
if (!allowQuickSwitch) {
return true;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 1f522c1..9a23557 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,6 +17,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
@@ -51,8 +52,10 @@
import android.graphics.Region;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.os.UserManager;
import android.provider.Settings;
import android.view.MotionEvent;
@@ -62,9 +65,9 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -108,6 +111,15 @@
private final boolean mIsOneHandedModeSupported;
private boolean mPipIsActive;
+ private boolean mIsUserUnlocked;
+ private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
+ private final SimpleBroadcastReceiver mUserUnlockedReceiver = new SimpleBroadcastReceiver(i -> {
+ if (ACTION_USER_UNLOCKED.equals(i.getAction())) {
+ mIsUserUnlocked = true;
+ notifyUserUnlocked();
+ }
+ });
+
private int mGestureBlockingTaskId = -1;
private @NonNull Region mExclusionRegion = new Region();
private SystemGestureExclusionListenerCompat mExclusionListener;
@@ -133,6 +145,14 @@
runOnDestroy(mRotationTouchHelper::destroy);
}
+ // Register for user unlocked if necessary
+ mIsUserUnlocked = context.getSystemService(UserManager.class)
+ .isUserUnlocked(Process.myUserHandle());
+ if (!mIsUserUnlocked) {
+ mUserUnlockedReceiver.register(mContext, ACTION_USER_UNLOCKED);
+ }
+ runOnDestroy(() -> mUserUnlockedReceiver.unregisterReceiverSafely(mContext));
+
// Register for exclusion updates
mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) {
@Override
@@ -292,12 +312,39 @@
}
/**
+ * Adds a callback for when a user is unlocked. If the user is already unlocked, this listener
+ * will be called back immediately.
+ */
+ public void runOnUserUnlocked(Runnable action) {
+ if (mIsUserUnlocked) {
+ action.run();
+ } else {
+ mUserUnlockedActions.add(action);
+ }
+ }
+
+ /**
+ * @return whether the user is unlocked.
+ */
+ public boolean isUserUnlocked() {
+ return mIsUserUnlocked;
+ }
+
+ /**
* @return whether the user has completed setup wizard
*/
public boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
+ private void notifyUserUnlocked() {
+ for (Runnable action : mUserUnlockedActions) {
+ action.run();
+ }
+ mUserUnlockedActions.clear();
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext);
+ }
+
/**
* Sets the task id where gestures should be blocked
*/
@@ -542,7 +589,7 @@
pw.println(" assistantAvailable=" + mAssistantAvailable);
pw.println(" assistantDisabled="
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
- pw.println(" isUserUnlocked=" + LockedUserState.get(mContext).isUserUnlocked());
+ pw.println(" isUserUnlocked=" + mIsUserUnlocked);
pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
pw.println(" deferredGestureRegion=" + mDeferredGestureRegion.getBounds());
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1b8a93c..61caef2 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -88,7 +88,6 @@
import com.android.launcher3.tracing.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
@@ -412,8 +411,8 @@
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
- LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
- LockedUserState.get(this).runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
+ mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
+ mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
ProtoTracer.INSTANCE.get(this).add(this);
@@ -483,7 +482,7 @@
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
- if (!LockedUserState.get(this).isUserUnlocked() || mDeviceState.isButtonNavMode()) {
+ if (!mDeviceState.isUserUnlocked() || mDeviceState.isButtonNavMode()) {
// Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
// mode doesn't have gestures
return;
@@ -526,7 +525,7 @@
@UiThread
private void onSystemUiFlagsChanged(int lastSysUIFlags) {
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
@@ -571,7 +570,7 @@
@UiThread
private void onAssistantVisibilityChanged() {
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
mDeviceState.getAssistantVisibility());
}
@@ -581,7 +580,7 @@
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
sIsInitialized = false;
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
mOverviewComponentObserver.onDestroy();
}
@@ -615,7 +614,7 @@
TestLogging.recordMotionEvent(
TestProtocol.SEQUENCE_TIS, "TouchInteractionService.onInputEvent", event);
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
@@ -637,8 +636,7 @@
mGestureState = newGestureState;
mConsumer = newConsumer(prevGestureState, mGestureState, event);
mUncheckedConsumer = mConsumer;
- } else if (LockedUserState.get(this).isUserUnlocked()
- && mDeviceState.isFullyGesturalNavMode()
+ } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
&& mDeviceState.canTriggerAssistantAction(event)) {
mGestureState = createGestureState(mGestureState);
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
@@ -758,7 +756,7 @@
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
CompoundString reasonString = newCompoundString("device locked");
InputConsumer consumer;
if (canStartSystemGesture) {
@@ -1105,7 +1103,7 @@
}
private void preloadOverview(boolean fromInit, boolean forSUWAllSet) {
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
@@ -1137,7 +1135,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
- if (!LockedUserState.get(this).isUserUnlocked()) {
+ if (!mDeviceState.isUserUnlocked()) {
return;
}
final BaseActivityInterface activityInterface =
@@ -1178,7 +1176,7 @@
} else {
// Dump everything
FeatureFlags.dump(pw);
- if (LockedUserState.get(this).isUserUnlocked()) {
+ if (mDeviceState.isUserUnlocked()) {
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
}
mDeviceState.dump(pw);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 0e2f020..df67b99 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -431,9 +431,12 @@
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
- setWillNotDraw(!FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get());
+ boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+ || DesktopTaskView.DESKTOP_MODE_SUPPORTED;
- mBorderAnimator = !FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+ setWillNotDraw(!keyboardFocusHighlightEnabled);
+
+ mBorderAnimator = !keyboardFocusHighlightEnabled
? null
: new BorderAnimator(
/* borderBoundsBuilder= */ this::updateBorderBounds,
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index edbce10..b109e8a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -104,6 +104,10 @@
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
private float mTranslationXForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationYForTaskbarAlignmentAnimation = 0f;
+
+ private float mTranslationXForTaskbarRevealAnimation = 0f;
+ private float mTranslationYForTaskbarRevealAnimation = 0f;
private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
@@ -952,11 +956,17 @@
}
private void updateTranslation() {
- super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
+ super.setTranslationX(mTranslationForReorderBounce.x
+ + mTranslationForReorderPreview.x
+ mTranslationForMoveFromCenterAnimation.x
- + mTranslationXForTaskbarAlignmentAnimation);
- super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
- + mTranslationForMoveFromCenterAnimation.y);
+ + mTranslationXForTaskbarAlignmentAnimation
+ + mTranslationXForTaskbarRevealAnimation
+ );
+ super.setTranslationY(mTranslationForReorderBounce.y
+ + mTranslationForReorderPreview.y
+ + mTranslationForMoveFromCenterAnimation.y
+ + mTranslationYForTaskbarAlignmentAnimation
+ + mTranslationYForTaskbarRevealAnimation);
}
public void setReorderBounceOffset(float x, float y) {
@@ -1012,6 +1022,51 @@
return mTranslationXForTaskbarAlignmentAnimation;
}
+ /**
+ * Sets translationX for taskbar to launcher alignment animation
+ */
+ public void setTranslationYForTaskbarAlignmentAnimation(float translationY) {
+ mTranslationYForTaskbarAlignmentAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY value for taskbar to launcher alignment animation
+ */
+ public float getTranslationYForTaskbarAlignmentAnimation() {
+ return mTranslationYForTaskbarAlignmentAnimation;
+ }
+
+ /**
+ * Sets translationX value for taskbar reveal animation
+ */
+ public void setTranslationXForTaskbarRevealAnimation(float translationX) {
+ mTranslationXForTaskbarRevealAnimation = translationX;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar reveal animation
+ */
+ public float getTranslationXForTaskbarRevealAnimation() {
+ return mTranslationXForTaskbarRevealAnimation;
+ }
+
+ /**
+ * Sets translationY value for taskbar reveal animation
+ */
+ public void setTranslationYForTaskbarRevealAnimation(float translationY) {
+ mTranslationYForTaskbarRevealAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY values for taskbar reveal animation
+ */
+ public float getTranslationYForTaskbarRevealAnimation() {
+ return mTranslationYForTaskbarRevealAnimation;
+ }
+
public View getView() {
return this;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2c34b3f..e63b054 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1315,23 +1315,29 @@
hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx;
int hotseatWidth = getHotseatRequiredWidth();
- int leftSpacing = (availableWidthPx - hotseatWidth) / 2;
- int rightSpacing = leftSpacing;
+ int startSpacing;
+ int endSpacing;
// Hotseat aligns to the left with nav buttons
if (hotseatBarEndOffset > 0) {
- leftSpacing = inlineNavButtonsEndSpacing;
- rightSpacing = availableWidthPx - hotseatWidth - leftSpacing + hotseatBorderSpace;
+ startSpacing = inlineNavButtonsEndSpacing;
+ endSpacing = availableWidthPx - hotseatWidth - startSpacing + hotseatBorderSpace;
+ } else {
+ startSpacing = (availableWidthPx - hotseatWidth) / 2;
+ endSpacing = startSpacing;
}
+ startSpacing += getAdditionalQsbSpace();
- hotseatBarPadding.set(leftSpacing, hotseatBarTopPadding, rightSpacing,
- hotseatBarBottomPadding);
-
+ hotseatBarPadding.top = hotseatBarTopPadding;
+ hotseatBarPadding.bottom = hotseatBarBottomPadding;
boolean isRtl = Utilities.isRtl(context.getResources());
if (isRtl) {
- hotseatBarPadding.right += getAdditionalQsbSpace();
+ hotseatBarPadding.left = endSpacing;
+ hotseatBarPadding.right = startSpacing;
} else {
- hotseatBarPadding.left += getAdditionalQsbSpace();
+ hotseatBarPadding.left = startSpacing;
+ hotseatBarPadding.right = endSpacing;
}
+
} else if (isScalableGrid) {
int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2;
hotseatBarPadding.set(sideSpacing,
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 2fb0fa6..604c1b8 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherPrefs.GRID_NAME;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.config.FeatureFlags.ENABLE_DEVICE_PROFILE_LOGGING;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
@@ -94,6 +93,8 @@
public static final int TYPE_MULTI_DISPLAY = 1;
public static final int TYPE_TABLET = 2;
+ private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
+
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
// Constants that affects the interpolation curve between statically defined device profile
@@ -206,7 +207,8 @@
String gridName = getCurrentGridName(context);
String newGridName = initGrid(context, gridName);
if (!newGridName.equals(gridName)) {
- LauncherPrefs.get(context).put(GRID_NAME, newGridName);
+ LauncherPrefs.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName)
+ .apply();
}
new DeviceGridState(this).writeToPrefs(context);
@@ -314,7 +316,7 @@
}
public static String getCurrentGridName(Context context) {
- return LauncherPrefs.get(context).get(GRID_NAME);
+ return LauncherPrefs.getPrefs(context).getString(KEY_IDP_GRID_NAME, null);
}
private String initGrid(Context context, String gridName) {
@@ -456,8 +458,9 @@
public void setCurrentGrid(Context context, String gridName) {
- LauncherPrefs.get(context).put(GRID_NAME, gridName);
- MAIN_EXECUTOR.execute(() -> onConfigChanged(context.getApplicationContext()));
+ Context appContext = context.getApplicationContext();
+ LauncherPrefs.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
+ MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
}
private Object[] toModelState() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8097fd7..8e53101 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1947,7 +1947,7 @@
Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(info.componentName);
setWaitingForResult(PendingRequestArgs.forIntent(REQUEST_CREATE_SHORTCUT, intent, info));
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: processShortcutFromDrop");
- if (!info.activityInfo.startConfigActivity(this, REQUEST_CREATE_SHORTCUT)) {
+ if (!info.getActivityInfo(this).startConfigActivity(this, REQUEST_CREATE_SHORTCUT)) {
handleActivityResult(REQUEST_CREATE_SHORTCUT, RESULT_CANCELED, null);
}
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index befaa64..2e07e30 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -4,8 +4,6 @@
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.annotation.VisibleForTesting
-import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
-import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
import com.android.launcher3.allapps.WorkProfileManager
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
@@ -22,10 +20,11 @@
class LauncherPrefs(private val context: Context) {
/** Wrapper around `getInner` for a `ContextualItem` */
- fun <T> get(item: ContextualItem<T>): T = getInner(item, item.defaultValueFromContext(context))
+ fun <T : Any> get(item: ContextualItem<T>): T =
+ getInner(item, item.defaultValueFromContext(context))
/** Wrapper around `getInner` for an `Item` */
- fun <T> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
+ fun <T : Any> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
/**
* Retrieves the value for an [Item] from [SharedPreferences]. It handles method typing via the
@@ -33,11 +32,11 @@
* `String`, `Boolean`, `Float`, `Int`, `Long`, or `Set<String>`.
*/
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
- private fun <T> getInner(item: Item, default: T): T {
+ private fun <T : Any> getInner(item: Item, default: T): T {
val sp = context.getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE)
- return when (item.type) {
- String::class.java -> sp.getString(item.sharedPrefKey, default as? String)
+ return when (default::class.java) {
+ String::class.java -> sp.getString(item.sharedPrefKey, default as String)
Boolean::class.java,
java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, default as Boolean)
Int::class.java,
@@ -46,10 +45,11 @@
java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, default as Float)
Long::class.java,
java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, default as Long)
- Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as? Set<String>)
+ Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as Set<String>)
else ->
throw IllegalArgumentException(
- "item type: ${item.type}" + " is not compatible with sharedPref methods"
+ "item type: ${default::class.java}" +
+ " is not compatible with sharedPref methods"
)
}
as T
@@ -224,36 +224,39 @@
backedUpItem(RestoreDbTask.RESTORED_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE)
@JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
@JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
- @JvmField val GRID_NAME = ConstantItem("idp_grid_name", true, null, String::class.java)
@JvmField
val ALLOW_ROTATION =
- backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
+ backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY) {
RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
}
@VisibleForTesting
@JvmStatic
fun <T> backedUpItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
- ConstantItem(sharedPrefKey, true, defaultValue)
+ ConstantItem(sharedPrefKey, LauncherFiles.SHARED_PREFERENCES_KEY, defaultValue)
@JvmStatic
fun <T> backedUpItem(
sharedPrefKey: String,
- type: Class<out T>,
defaultValueFromContext: (c: Context) -> T
- ): ContextualItem<T> = ContextualItem(sharedPrefKey, true, defaultValueFromContext, type)
+ ): ContextualItem<T> =
+ ContextualItem(
+ sharedPrefKey,
+ LauncherFiles.SHARED_PREFERENCES_KEY,
+ defaultValueFromContext
+ )
@VisibleForTesting
@JvmStatic
fun <T> nonRestorableItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
- ConstantItem(sharedPrefKey, false, defaultValue)
+ ConstantItem(sharedPrefKey, LauncherFiles.DEVICE_PREFERENCES_KEY, defaultValue)
@Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.")
@JvmStatic
fun getPrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so we use single cached instance
return context.applicationContext.getSharedPreferences(
- SHARED_PREFERENCES_KEY,
+ LauncherFiles.SHARED_PREFERENCES_KEY,
Context.MODE_PRIVATE
)
}
@@ -263,7 +266,7 @@
fun getDevicePrefs(context: Context): SharedPreferences {
// Use application context for shared preferences, so we use a single cached instance
return context.applicationContext.getSharedPreferences(
- DEVICE_PREFERENCES_KEY,
+ LauncherFiles.DEVICE_PREFERENCES_KEY,
Context.MODE_PRIVATE
)
}
@@ -272,26 +275,21 @@
abstract class Item {
abstract val sharedPrefKey: String
- abstract val isBackedUp: Boolean
- abstract val type: Class<*>
- val sharedPrefFile: String = if (isBackedUp) SHARED_PREFERENCES_KEY else DEVICE_PREFERENCES_KEY
+ abstract val sharedPrefFile: String
fun <T> to(value: T): Pair<Item, T> = Pair(this, value)
}
data class ConstantItem<T>(
override val sharedPrefKey: String,
- override val isBackedUp: Boolean,
- val defaultValue: T,
- // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
- override val type: Class<out T> = defaultValue!!::class.java
+ override val sharedPrefFile: String,
+ val defaultValue: T
) : Item()
data class ContextualItem<T>(
override val sharedPrefKey: String,
- override val isBackedUp: Boolean,
- private val defaultSupplier: (c: Context) -> T,
- override val type: Class<out T>
+ override val sharedPrefFile: String,
+ private val defaultSupplier: (c: Context) -> T
) : Item() {
private var default: T? = null
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index b7a22fc..000ddd8 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -21,7 +21,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import java.util.Optional;
@@ -29,13 +29,20 @@
* Meta data that is used for deferred binding. e.g., this object is used to pass information on
* draggable targets when they are dropped onto the workspace from another container.
*/
-public class PendingAddItemInfo extends ItemInfo {
+public class PendingAddItemInfo extends ItemInfoWithIcon {
/**
* The component that will be created.
*/
public ComponentName componentName;
+ public PendingAddItemInfo() { }
+
+ public PendingAddItemInfo(PendingAddItemInfo info) {
+ super(info);
+ componentName = info.componentName;
+ }
+
@Override
protected String dumpProperties() {
return super.dumpProperties() + " componentName=" + componentName;
@@ -46,13 +53,18 @@
*/
@NonNull
@Override
- public ItemInfo makeShallowCopy() {
+ public PendingAddItemInfo makeShallowCopy() {
PendingAddItemInfo itemInfo = new PendingAddItemInfo();
itemInfo.copyFrom(this);
itemInfo.componentName = this.componentName;
return itemInfo;
}
+ @Override
+ public PendingAddItemInfo clone() {
+ return makeShallowCopy();
+ }
+
@Nullable
@Override
public ComponentName getTargetComponent() {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index bd9493b..b32ff3c 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -557,6 +557,12 @@
int width, int height, Object[] outObj) {
ActivityContext activity = ActivityContext.lookupContext(context);
LauncherAppState appState = LauncherAppState.getInstance(context);
+ if (info instanceof PendingAddShortcutInfo) {
+ ShortcutConfigActivityInfo activityInfo =
+ ((PendingAddShortcutInfo) info).getActivityInfo(context);
+ outObj[0] = activityInfo;
+ return activityInfo.getFullResIcon(appState.getIconCache());
+ }
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
LauncherActivityInfo activityInfo = context.getSystemService(LauncherApps.class)
.resolveActivity(info.getIntent(), info.user);
@@ -565,12 +571,6 @@
.getIconProvider().getIcon(
activityInfo, activity.getDeviceProfile().inv.fillResIconDpi);
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- if (info instanceof PendingAddShortcutInfo) {
- ShortcutConfigActivityInfo activityInfo =
- ((PendingAddShortcutInfo) info).activityInfo;
- outObj[0] = activityInfo;
- return activityInfo.getFullResIcon(appState.getIconCache());
- }
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
.buildRequest(context)
.query(ShortcutRequest.ALL);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index cfb8ca4..ba492d5 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2690,7 +2690,7 @@
private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) {
if (d.dragInfo instanceof PendingAddShortcutInfo) {
WorkspaceItemInfo si = ((PendingAddShortcutInfo) d.dragInfo)
- .activityInfo.createWorkspaceItemInfo();
+ .getActivityInfo(mLauncher).createWorkspaceItemInfo();
if (si != null) {
d.dragInfo = si;
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 14e3fa6..45d532d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -360,6 +360,9 @@
mAH.get(i).mRecyclerView.scrollToTop();
}
}
+ if (mTouchHandler != null) {
+ mTouchHandler.endFastScrolling();
+ }
if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
mHeader.reset(animate);
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index f54d05d..e10fdf5 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -56,7 +56,6 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
@@ -218,12 +217,6 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public void setItemInfo(final ItemInfo info) {
- if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
- && info.itemType != LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
- return;
- }
// Load the adaptive icon on a background thread and add the view in ui thread.
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
Object[] outObj = new Object[1];
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index f9916d0..6b21522 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -44,7 +44,7 @@
* request.
*/
@TargetApi(Build.VERSION_CODES.O)
-class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
+public class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo {
// Class name used in the target component, such that it will never represent an
// actual existing class.
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 9a5d77e..c9fe745 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1263,7 +1263,7 @@
PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
? (PendingAddShortcutInfo) d.dragInfo : null;
WorkspaceItemInfo pasiSi =
- pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
+ pasi != null ? pasi.getActivityInfo(launcher).createWorkspaceItemInfo() : null;
if (pasi != null && pasiSi == null) {
// There is no WorkspaceItemInfo, so we have to go through a configuration activity.
pasi.container = mInfo.id;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index e69f781..ee1a060 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -135,6 +135,9 @@
private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0);
private float mTranslationXForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationYForTaskbarAlignmentAnimation = 0f;
+ private float mTranslationXForTaskbarRevealAnimation = 0f;
+ private float mTranslationYForTaskbarRevealAnimation = 0f;
private final PointF mTranslationForReorderBounce = new PointF(0, 0);
private final PointF mTranslationForReorderPreview = new PointF(0, 0);
@@ -416,7 +419,7 @@
() -> {
mPreviewItemManager.hidePreviewItem(finalIndex, false);
mFolder.showItem(item);
- },
+ },
DragLayer.ANIMATION_END_DISAPPEAR, null);
mFolder.hideItem(item);
@@ -768,11 +771,15 @@
}
private void updateTranslation() {
- super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x
+ super.setTranslationX(mTranslationForReorderBounce.x
+ + mTranslationForReorderPreview.x
+ mTranslationForMoveFromCenterAnimation.x
- + mTranslationXForTaskbarAlignmentAnimation);
+ + mTranslationXForTaskbarAlignmentAnimation
+ + mTranslationXForTaskbarRevealAnimation);
super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y
- + mTranslationForMoveFromCenterAnimation.y);
+ + mTranslationForMoveFromCenterAnimation.y
+ + mTranslationYForTaskbarAlignmentAnimation
+ + mTranslationYForTaskbarRevealAnimation);
}
public void setReorderBounceOffset(float x, float y) {
@@ -787,7 +794,7 @@
/**
* Sets translationX value for taskbar to launcher alignment animation
*/
- public void setTranslationForTaskbarAlignmentAnimation(float translationX) {
+ public void setTranslationXForTaskbarAlignmentAnimation(float translationX) {
mTranslationXForTaskbarAlignmentAnimation = translationX;
updateTranslation();
}
@@ -800,6 +807,51 @@
}
/**
+ * Sets translationY value for taskbar to launcher alignment animation
+ */
+ public void setTranslationYForTaskbarAlignmentAnimation(float translationY) {
+ mTranslationYForTaskbarAlignmentAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar to launcher alignment animation
+ */
+ public float getTranslationYForTaskbarAlignmentAnimation() {
+ return mTranslationYForTaskbarAlignmentAnimation;
+ }
+
+ /**
+ * Sets translationX value for taskbar reveal animation
+ */
+ public void setTranslationXForTaskbarRevealAnimation(float translationX) {
+ mTranslationXForTaskbarRevealAnimation = translationX;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translation values for taskbar reveal animation
+ */
+ public float getTranslationXForTaskbarRevealAnimation() {
+ return mTranslationXForTaskbarRevealAnimation;
+ }
+
+ /**
+ * Sets translationY value for taskbar reveal animation
+ */
+ public void setTranslationYForTaskbarRevealAnimation(float translationY) {
+ mTranslationYForTaskbarRevealAnimation = translationY;
+ updateTranslation();
+ }
+
+ /**
+ * Returns translationY values for taskbar reveal animation
+ */
+ public float getTranslationYForTaskbarRevealAnimation() {
+ return mTranslationYForTaskbarRevealAnimation;
+ }
+
+ /**
* Sets translation values for move from center animation
*/
public void setTranslationForMoveFromCenterAnimation(float x, float y) {
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 9426c22..2c8f1f3 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -138,12 +138,14 @@
}
idp.setCurrentGrid(getContext(), gridName);
+ getContext().getContentResolver().notifyChange(uri, null);
return 1;
}
case ICON_THEMED:
case SET_ICON_THEMED: {
LauncherPrefs.get(getContext())
.put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE));
+ getContext().getContentResolver().notifyChange(uri, null);
return 1;
}
default:
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 0b4a4a5..3c63f26 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -60,6 +60,7 @@
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.InstantAppResolver;
@@ -81,6 +82,11 @@
*/
public class IconCache extends BaseIconCache {
+ // Shortcut extra which can point to a packageName and can be used to indicate an alternate
+ // badge info. Launcher only reads this if the shortcut comes from a system app.
+ public static final String EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
+ "extra_shortcut_badge_override_package";
+
private static final String TAG = "Launcher.IconCache";
private final Predicate<ItemInfoWithIcon> mIsUsingFallbackOrNonDefaultIconCheck = w ->
@@ -260,8 +266,15 @@
getTitleAndIcon(appInfo, false);
return appInfo.bitmap;
} else {
- PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage(),
- shortcutInfo.getUserHandle());
+ String pkg = shortcutInfo.getPackage();
+ String override = shortcutInfo.getExtras() == null ? null
+ : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
+ if (!TextUtils.isEmpty(override)
+ && InstallSessionHelper.INSTANCE.get(mContext)
+ .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
+ pkg = override;
+ }
+ PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle());
getTitleAndIconForApp(pkgInfo, false);
return pkgInfo.bitmap;
}
@@ -484,8 +497,7 @@
WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext)
.get(infoInOut.widgetCategory);
infoInOut.title = mContext.getString(widgetSection.mSectionTitle);
- infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
- infoInOut.title, infoInOut.user);
+ infoInOut.contentDescription = getUserBadgedLabel(infoInOut.title, infoInOut.user);
final BitmapInfo cachedBitmap = mWidgetCategoryBitmapInfos.get(infoInOut.widgetCategory);
if (cachedBitmap != null) {
infoInOut.bitmap = getBadgedIcon(cachedBitmap, infoInOut.user);
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 0a6a7cd..855a69d 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -310,7 +310,7 @@
throw new InvalidParameterException("Invalid restoreType " + restoreFlag);
}
- info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
+ info.contentDescription = mIconCache.getUserBadgedLabel(info.title, info.user);
info.itemType = itemType;
info.status = restoreFlag;
return info;
@@ -381,7 +381,7 @@
}
}
- info.contentDescription = mPM.getUserBadgedLabel(info.title, info.user);
+ info.contentDescription = mIconCache.getUserBadgedLabel(info.title, info.user);
return info;
}
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index db23566..7ca3b11 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -171,15 +171,22 @@
}
return null;
}
- String pkg = sessionInfo.getInstallerPackageName();
+ return isTrustedPackage(sessionInfo.getInstallerPackageName(), getUserHandle(sessionInfo))
+ ? sessionInfo : null;
+ }
+
+ /**
+ * Returns true if the provided packageName can be trusted for user configurations
+ */
+ public boolean isTrustedPackage(String pkg, UserHandle user) {
synchronized (mSessionVerifiedMap) {
if (!mSessionVerifiedMap.containsKey(pkg)) {
boolean hasSystemFlag = new PackageManagerHelper(mAppContext).getApplicationInfo(
- pkg, getUserHandle(sessionInfo), ApplicationInfo.FLAG_SYSTEM) != null;
+ pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
}
}
- return mSessionVerifiedMap.get(pkg) ? sessionInfo : null;
+ return mSessionVerifiedMap.get(pkg);
}
@NonNull
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 7af14c6..14e67b2 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -112,26 +111,6 @@
return true;
}
- static class ShortcutConfigActivityInfoVL extends ShortcutConfigActivityInfo {
-
- private final ActivityInfo mInfo;
-
- ShortcutConfigActivityInfoVL(ActivityInfo info) {
- super(new ComponentName(info.packageName, info.name), Process.myUserHandle());
- mInfo = info;
- }
-
- @Override
- public CharSequence getLabel(PackageManager pm) {
- return mInfo.loadLabel(pm);
- }
-
- @Override
- public Drawable getFullResIcon(IconCache cache) {
- return cache.getFullResIcon(mInfo);
- }
- }
-
@TargetApi(26)
public static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
deleted file mode 100644
index 7b49583..0000000
--- a/src/com/android/launcher3/util/LockedUserState.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.android.launcher3.util
-
-import android.content.Context
-import android.content.Intent
-import android.os.Process
-import android.os.UserManager
-import androidx.annotation.VisibleForTesting
-
-class LockedUserState(private val mContext: Context) : SafeCloseable {
- var isUserUnlocked: Boolean
- private set
- private val mUserUnlockedActions: RunnableList = RunnableList()
-
- @VisibleForTesting
- val mUserUnlockedReceiver = SimpleBroadcastReceiver {
- if (Intent.ACTION_USER_UNLOCKED == it.action) {
- isUserUnlocked = true
- notifyUserUnlocked()
- }
- }
-
- init {
- isUserUnlocked =
- mContext
- .getSystemService(UserManager::class.java)!!
- .isUserUnlocked(Process.myUserHandle())
- if (isUserUnlocked) {
- notifyUserUnlocked()
- } else {
- mUserUnlockedReceiver.register(mContext, Intent.ACTION_USER_UNLOCKED)
- }
- }
-
- private fun notifyUserUnlocked() {
- mUserUnlockedActions.executeAllAndDestroy()
- mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
- }
-
- /** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */
- override fun close() {
- mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
- }
-
- /**
- * Adds a `Runnable` to be executed when a user is unlocked. If the user is already unlocked,
- * this runnable will run immediately because RunnableList will already have been destroyed.
- */
- fun runOnUserUnlocked(action: Runnable) {
- mUserUnlockedActions.add(action)
- }
-
- companion object {
- @VisibleForTesting val INSTANCE = MainThreadInitializedObject { LockedUserState(it) }
-
- @JvmStatic fun get(context: Context): LockedUserState = INSTANCE.get(context)
- }
-}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index f7837f5..b6f6223 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -313,7 +313,7 @@
*/
default boolean startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
-
+ Preconditions.assertUIThread();
Context context = (Context) this;
if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 3af2e3c..ead6886 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -283,15 +283,7 @@
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mRv.onFastScrollCompleted();
- mTouchOffsetY = 0;
- mLastTouchY = 0;
- mIgnoreDragGesture = false;
- if (mIsDragging) {
- mIsDragging = false;
- animatePopupVisibility(false);
- showActiveScrollbar(false);
- }
+ endFastScrolling();
break;
}
if (DEBUG) {
@@ -330,6 +322,19 @@
setThumbOffsetY((int) mLastTouchY);
}
+ /** End any active fast scrolling touch handling, if applicable. */
+ public void endFastScrolling() {
+ mRv.onFastScrollCompleted();
+ mTouchOffsetY = 0;
+ mLastTouchY = 0;
+ mIgnoreDragGesture = false;
+ if (mIsDragging) {
+ mIsDragging = false;
+ animatePopupVisibility(false);
+ showActiveScrollbar(false);
+ }
+ }
+
public void onDraw(Canvas canvas) {
if (mThumbOffsetY < 0) {
return;
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index 9601652..3935be5 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -17,6 +17,8 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
+import android.content.Context;
+
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
@@ -27,13 +29,28 @@
*/
public class PendingAddShortcutInfo extends PendingAddItemInfo {
- public ShortcutConfigActivityInfo activityInfo;
+ // TODO: Make it @NonNull
+ protected ShortcutConfigActivityInfo mActivityInfo;
public PendingAddShortcutInfo(ShortcutConfigActivityInfo activityInfo) {
- this.activityInfo = activityInfo;
+ this.mActivityInfo = activityInfo;
componentName = activityInfo.getComponent();
user = activityInfo.getUser();
itemType = activityInfo.getItemType();
this.container = CONTAINER_WIDGETS_TRAY;
}
+
+ public PendingAddShortcutInfo(PendingAddShortcutInfo info) {
+ super(info);
+ mActivityInfo = info.mActivityInfo;
+ }
+
+ public PendingAddShortcutInfo() { }
+
+ /**
+ * Returns the info used for creating the shortcut
+ */
+ public ShortcutConfigActivityInfo getActivityInfo(Context context) {
+ return mActivityInfo;
+ }
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index bbbc329..2dedd12 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -180,7 +180,8 @@
draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
- Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
+ Drawable icon = createShortcutInfo.getActivityInfo(launcher)
+ .getFullResIcon(app.getIconCache());
LauncherIcons li = LauncherIcons.obtain(launcher);
preview = new FastBitmapDrawable(
li.createScaledBitmap(icon, BaseIconFactory.MODE_DEFAULT));
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index d40a7bc..31e8d30 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -13,7 +13,7 @@
private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false)
private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)")
private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1)
-private val TEST_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, Boolean::class.java)
+private val TEST_CONTEXTUAL_ITEM = LauncherPrefs.backedUpItem("4") { true }
@SmallTest
@RunWith(AndroidJUnit4::class)
diff --git a/tests/src/com/android/launcher3/util/LockedUserStateTest.kt b/tests/src/com/android/launcher3/util/LockedUserStateTest.kt
deleted file mode 100644
index 84156e7..0000000
--- a/tests/src/com/android/launcher3/util/LockedUserStateTest.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.util
-
-import android.content.Context
-import android.content.Intent
-import android.os.Process
-import android.os.UserManager
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations
-
-/** Unit tests for {@link LockedUserUtil} */
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LockedUserStateTest {
-
- @Mock lateinit var userManager: UserManager
- @Mock lateinit var context: Context
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- `when`(context.getSystemService(UserManager::class.java)).thenReturn(userManager)
- }
-
- @Test
- fun runOnUserUnlocked_runs_action_immediately_if_already_unlocked() {
- `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(true)
- LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
- val action: Runnable = mock()
-
- LockedUserState.get(context).runOnUserUnlocked(action)
- verify(action).run()
- }
-
- @Test
- fun runOnUserUnlocked_waits_to_run_action_until_user_is_unlocked() {
- `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(false)
- LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
- val action: Runnable = mock()
-
- LockedUserState.get(context).runOnUserUnlocked(action)
- verifyZeroInteractions(action)
-
- LockedUserState.get(context)
- .mUserUnlockedReceiver
- .onReceive(context, Intent(Intent.ACTION_USER_UNLOCKED))
-
- verify(action).run()
- }
-
- @Test
- fun isUserUnlocked_returns_true_when_user_is_unlocked() {
- `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(true)
- LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
- assertThat(LockedUserState.get(context).isUserUnlocked).isTrue()
- }
-
- @Test
- fun isUserUnlocked_returns_false_when_user_is_locked() {
- `when`(userManager.isUserUnlocked(Process.myUserHandle())).thenReturn(false)
- LockedUserState.INSTANCE.initializeForTesting(LockedUserState(context))
- assertThat(LockedUserState.get(context).isUserUnlocked).isFalse()
- }
-}