diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 097609f2d9..0f3474eb19 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -42,7 +42,6 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_A import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH; import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION; import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY; -import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS; import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.launcher3.testing.TestProtocol.BAD_STATE; @@ -105,7 +104,6 @@ import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.DynamicResource; -import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -195,9 +193,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private static final int WIDGET_CROSSFADE_DURATION_MILLIS = 125; protected final BaseQuickstepLauncher mLauncher; - private final DragLayer mDragLayer; - private final AlphaProperty mDragLayerAlpha; final Handler mHandler; @@ -241,7 +237,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener public QuickstepTransitionManager(Context context) { mLauncher = Launcher.cast(Launcher.getLauncher(context)); mDragLayer = mLauncher.getDragLayer(); - mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS); mHandler = new Handler(Looper.getMainLooper()); mDeviceProfile = mLauncher.getDeviceProfile(); mBackAnimationController = new LauncherBackAnimationController(mLauncher, this); diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index a9ae7bdc3f..b7978076c1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -176,7 +176,8 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT return revealAnim; } - public void onIsStashed(boolean isStashed) { + /** Called when taskbar is stashed or unstashed. */ + public void onIsStashedChanged(boolean isStashed) { mRegionSamplingHelper.setWindowVisible(isStashed); if (isStashed) { mStashedHandleView.updateSampledRegion(mStashedHandleBounds); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 9561b749f2..b349637c6b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -559,7 +559,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } } mWindowLayoutParams.height = height; - mControllers.taskbarInsetsController.onTaskbarWindowHeightChanged(); + mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 5d3a1520fc..ff08e3dda7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -160,6 +160,7 @@ public class TaskbarControllers { taskbarForceVisibleImmersiveController.onDestroy(); taskbarAllAppsController.onDestroy(); navButtonController.onDestroy(); + taskbarInsetsController.onDestroy(); mControllersToLog = null; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index 089c26d3f9..c1a6185d23 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -83,7 +83,6 @@ public class TaskbarDragLayer extends BaseDragLayer { private void onComputeTaskbarInsets(InsetsInfo insetsInfo) { if (mControllerCallbacks != null) { mControllerCallbacks.updateInsetsTouchability(insetsInfo); - mControllerCallbacks.updateContentInsets(insetsInfo.contentInsets); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 307f674ee6..3e2695c135 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -163,16 +163,6 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa mControllers.taskbarInsetsController.updateInsetsTouchability(insetsInfo); } - /** - * Called to update the {@link InsetsInfo#contentInsets}. This is reported to apps but our - * internal launcher will ignore these insets. - */ - public void updateContentInsets(Rect outContentInsets) { - int contentHeight = mControllers.taskbarStashController - .getContentHeightToReportToApps(); - outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight; - } - /** * Called when a child is removed from TaskbarDragLayer. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index a2ff7806f7..9870a2e0bf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -18,6 +18,7 @@ package com.android.launcher3.taskbar import android.graphics.Insets import android.view.WindowManager import com.android.launcher3.AbstractFloatingView +import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS import com.android.launcher3.R import com.android.launcher3.anim.AlphaUpdateListener import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController @@ -53,19 +54,39 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask ) ) + windowLayoutParams.providedInternalInsets = arrayOfNulls(ITYPE_SIZE) windowLayoutParams.providedInternalImeInsets = arrayOfNulls(ITYPE_SIZE) - onTaskbarWindowHeightChanged() + onTaskbarWindowHeightOrInsetsChanged() windowLayoutParams.insetsRoundedCornerFrame = true } - fun onTaskbarWindowHeightChanged() { - val reducingSize = Insets.of(0, windowLayoutParams.height - taskbarHeightForIme, 0, 0) + fun onDestroy() {} + + fun onTaskbarWindowHeightOrInsetsChanged() { + var reducingSize = getReducingInsetsForTaskbarInsetsHeight( + controllers.taskbarStashController.contentHeightToReportToApps) + windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize + reducingSize = getReducingInsetsForTaskbarInsetsHeight( + controllers.taskbarStashController.tappableHeightToReportToApps) + windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize + + reducingSize = getReducingInsetsForTaskbarInsetsHeight(taskbarHeightForIme) windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize } + /** + * WindowLayoutParams.providedInternal*Insets expects Insets that subtract from the window frame + * height (i.e. WindowLayoutParams#height). So for Taskbar to report bottom insets to apps, it + * actually provides insets from the top of its window frame. + * @param height The number of pixels from the bottom of the screen that Taskbar insets. + */ + private fun getReducingInsetsForTaskbarInsetsHeight(height: Int): Insets { + return Insets.of(0, windowLayoutParams.height - height, 0, 0) + } + /** * Called to update the touchable insets. * @see InsetsInfo.setTouchableInsets @@ -88,18 +109,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask } else if (controllers.taskbarDragController.isSystemDragInProgress) { // Let touches pass through us. insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION) - } else if (AbstractFloatingView.getOpenView( - context, - AbstractFloatingView.TYPE_TASKBAR_ALL_APPS - ) != null - ) { + } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_ALL_APPS)) { // Let touches pass through us. insetsInfo.setTouchableInsets(InsetsInfo.TOUCHABLE_INSETS_REGION) } else if (controllers.taskbarViewController.areIconsVisible() - || AbstractFloatingView.getOpenView( - context, - AbstractFloatingView.TYPE_ALL - ) != null + || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) || context.isNavBarKidsModeActive ) { // Taskbar has some touchable elements, take over the full taskbar area @@ -120,6 +134,10 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask override fun dumpLogs(prefix: String, pw: PrintWriter) { pw.println(prefix + "TaskbarInsetsController:") pw.println("$prefix\twindowHeight=${windowLayoutParams.height}") + pw.println("$prefix\tprovidedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" + + "${windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR]}") + pw.println("$prefix\tprovidedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" + + "${windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]}") pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]=" + "${windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR]}") pw.println("$prefix\tprovidedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT]=" + diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index be67136bf0..f1a226fe25 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.content.SharedPreferences; import android.util.Log; import android.view.ViewConfiguration; +import android.view.WindowInsets; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; @@ -280,6 +281,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Returns the height that taskbar will inset when inside apps. + * @see WindowInsets.Type#navigationBars() + * @see WindowInsets.Type#systemBars() */ public int getContentHeightToReportToApps() { if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) { @@ -304,6 +307,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return mUnstashedHeight; } + /** + * Returns the height that taskbar will inset when inside apps. + * @see WindowInsets.Type#tappableElement() + */ + public int getTappableHeightToReportToApps() { + int contentHeight = getContentHeightToReportToApps(); + return contentHeight <= mStashedHeight ? 0 : contentHeight; + } + public int getStashedHeight() { return mStashedHeight; } @@ -442,7 +454,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba @Override public void onAnimationStart(Animator animation) { mIsStashed = isStashed; - onIsStashed(mIsStashed); + onIsStashedChanged(mIsStashed); } @Override @@ -489,8 +501,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba .setDuration(TASKBAR_HINT_STASH_DURATION).start(); } - private void onIsStashed(boolean isStashed) { - mControllers.stashedHandleViewController.onIsStashed(isStashed); + private void onIsStashedChanged(boolean isStashed) { + mControllers.stashedHandleViewController.onIsStashedChanged(isStashed); + mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged(); } public void applyState() { diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 947d3e26da..86f26c3673 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -107,7 +107,6 @@ public final class RecentsViewStateController extends */ private void handleSplitSelectionState(@NonNull LauncherState toState, @Nullable PendingAnimation builder) { - LauncherState currentState = mLauncher.getStateManager().getState(); boolean animate = builder != null; PagedOrientationHandler orientationHandler = ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler(); @@ -116,7 +115,7 @@ public final class RecentsViewStateController extends TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION, mLauncher.getDeviceProfile()); - if (isSplitSelectionState(currentState, toState)) { + if (toState == OVERVIEW_SPLIT_SELECT) { // Animation to "dismiss" selected taskView PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation( toState.getTransitionDuration(mLauncher)); @@ -125,30 +124,18 @@ public final class RecentsViewStateController extends toState.getSplitSelectTranslation(mLauncher), LINEAR); splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR); - if (!animate && isSplitSelectionState(currentState, toState)) { + if (!animate) { splitSelectInitAnimation.buildAnim().start(); - } else if (animate && - isSplitSelectionState(currentState, toState)) { + } else { builder.add(splitSelectInitAnimation.buildAnim()); } - } - if (isSplitSelectionState(currentState, toState)) { mRecentsView.applySplitPrimaryScrollOffset(); } else { mRecentsView.resetSplitPrimaryScrollOffset(); } } - /** - * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT} - * and {@param fromState} is not {@link LauncherState#OVERVIEW_SPLIT_SELECT} - */ - private boolean isSplitSelectionState(@NonNull LauncherState fromState, - @NonNull LauncherState toState) { - return fromState != OVERVIEW_SPLIT_SELECT && toState == OVERVIEW_SPLIT_SELECT; - } - private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config, LauncherState state) { float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0; diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index 7bfb76a978..34a6821ac5 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -21,7 +21,8 @@ import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRES import static com.android.launcher3.LauncherAnimUtils.newCancelListener; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_PROGRESS; +import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_ALPHA; +import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_TRANSLATION; import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU; @@ -40,11 +41,9 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.util.TouchController; import com.android.quickstep.TaskUtils; @@ -148,16 +147,10 @@ public class NavBarToHomeTouchController implements TouchController, AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_TASK_MENU); } else if (mStartState == ALL_APPS) { AllAppsTransitionController allAppsController = mLauncher.getAllAppsController(); - builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_PROGRESS, - -mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR); - - // Slightly fade out all apps content to further distinguish from scrolling. - StateAnimationConfig config = new StateAnimationConfig(); - config.duration = accuracy; - config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators - .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f)); - - allAppsController.setAlphas(mEndState, config, builder); + builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_TRANSLATION, + -mPullbackDistance, PULLBACK_INTERPOLATOR); + builder.setFloat(allAppsController, ALL_APPS_PULL_BACK_ALPHA, + 0.5f, PULLBACK_INTERPOLATOR); } AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher); if (topView != null) { diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index b073b90baf..b90e8206f7 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1013,19 +1013,19 @@ public abstract class AbsSwipeUpHandler, return RECENTS; } final GestureEndTarget endTarget; - final boolean goingToNewTask; + final boolean canGoToNewTask; if (mRecentsView != null) { if (!hasTargets()) { // If there are no running tasks, then we can assume that this is a continuation of // the last gesture, but after the recents animation has finished - goingToNewTask = true; + canGoToNewTask = true; } else { final int runningTaskIndex = mRecentsView.getRunningTaskIndex(); final int taskToLaunch = mRecentsView.getNextPage(); - goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex; + canGoToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex; } } else { - goingToNewTask = false; + canGoToNewTask = false; } final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() @@ -1034,13 +1034,13 @@ public abstract class AbsSwipeUpHandler, if (isCancel) { endTarget = LAST_TASK; } else if (mDeviceState.isFullyGesturalNavMode()) { - if (goingToNewTask && isFlingX) { + if (canGoToNewTask && isFlingX) { // Flinging towards new task takes precedence over mIsMotionPaused (which only // checks y-velocity). endTarget = NEW_TASK; } else if (mIsMotionPaused) { endTarget = RECENTS; - } else if (goingToNewTask) { + } else if (canGoToNewTask) { endTarget = NEW_TASK; } else { endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME; @@ -1048,26 +1048,22 @@ public abstract class AbsSwipeUpHandler, } else { endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS - : goingToNewTask + : canGoToNewTask ? NEW_TASK : LAST_TASK; } } else { // If swiping at a diagonal, base end target on the faster velocity. boolean isSwipeUp = endVelocity < 0; - boolean willGoToNewTaskOnSwipeUp = - goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity); + boolean willGoToNewTask = + canGoToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity); - if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) { - endTarget = HOME; - } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) { - // If swiping at a diagonal, base end target on the faster velocity. - endTarget = NEW_TASK; + if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) { + endTarget = willGoToNewTask ? NEW_TASK : HOME; } else if (isSwipeUp) { - endTarget = !reachedOverviewThreshold && willGoToNewTaskOnSwipeUp - ? NEW_TASK : RECENTS; + endTarget = (!reachedOverviewThreshold && willGoToNewTask) ? NEW_TASK : RECENTS; } else { - endTarget = goingToNewTask ? NEW_TASK : LAST_TASK; + endTarget = willGoToNewTask ? NEW_TASK : LAST_TASK; // Swipe is downward. } } @@ -1145,6 +1141,8 @@ public abstract class AbsSwipeUpHandler, duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } } + } else if (endTarget == LAST_TASK && mRecentsView != null) { + mRecentsView.snapToPage(mRecentsView.getCurrentPage(), Math.toIntExact(duration)); } // Let RecentsView handle the scrolling to the task, which we launch in startNewTask() diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 5f715f812f..49bf827cf9 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1396,6 +1396,9 @@ public abstract class RecentsView diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index ae190c5db9..774977ce3f 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -32,7 +32,7 @@ "تقسيم لليسار" "تقسيم لليمين" "‏معلومات تطبيق %1$s" - "انقر مع الاستمرار لنقل أداة" + "انقر مع الاستمرار لنقل أداة." "انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة." "%1$d × %2$d" "‏العرض %1$d الطول %2$d" diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml index 49b34dd8f7..ddcb256753 100644 --- a/res/values-b+sr+Latn/strings.xml +++ b/res/values-b+sr+Latn/strings.xml @@ -47,7 +47,7 @@ "Pretražite" "Obrišite tekst iz okvira za pretragu" "Vidžeti i prečice nisu dostupni" - "Nije pronađen nijedan vidžet ili prečica" + "Nije pronađen nijedan vidžet ni prečica" "Lično" "Posao" "Konverzacije" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 82031a69b5..3b38e62286 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -32,7 +32,7 @@ "Rozdělit vlevo" "Rozdělit vpravo" "Informace o aplikaci %1$s" - "Klepnutím a podržením přesunete widget." + "Widget přesunete klepnutím a podržením." "Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce." "%1$d × %2$d" "šířka %1$d, výška %2$d" @@ -164,7 +164,7 @@ "Osobní" "Pracovní" "Pracovní profil" - "Pracovní aplikace jsou označené a viditelné vašemu administrátorovi IT" + "Pracovní aplikace jsou označené a váš administrátor IT je vidí" "Rozumím" "Pracovní aplikace jsou pozastaveny" "Pracovní aplikace vám nemohou zasílat oznámení, používat vaši baterii ani získat přístup k vaší poloze" diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml index e5eeb3b1df..90cd6cd498 100644 --- a/res/values-en-rXC/strings.xml +++ b/res/values-en-rXC/strings.xml @@ -124,14 +124,10 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ installing, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ downloading, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ waiting to install‎‏‎‎‏‎" - - - - - - - - + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎App update required‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎Update‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎Remove‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎Widgets list‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎Widgets list closed‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎Add to home screen‎‏‎‎‏‎" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 8572b6716e..a6f07da11b 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -23,8 +23,8 @@ "Trabajo" "La aplicación no está instalada." "La aplicación no está disponible" - "Aplicación descargada inhabilitada en modo seguro" - "Widgets inhabilitados en modo seguro" + "Aplicación descargada inhabilitada en modo Seguro" + "Widgets inhabilitados en modo Seguro" "Acceso directo no disponible" "Inicio" "Pantalla dividida" @@ -32,7 +32,7 @@ "Dividir parte izquierda" "Dividir parte derecha" "Información de la aplicación %1$s" - "Mantén pulsado un widget para moverlo." + "Mantén pulsado un widget para moverlo" "Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas." "%1$d × %2$d" "%1$d de ancho por %2$d de alto" @@ -41,7 +41,7 @@ "Añadir a pantalla de inicio" "Widget %1$s añadido a la pantalla de inicio" "{count,plural, =1{# widget}other{# widgets}}" - "{count,plural, =1{# combinación de teclas}other{# combinaciones de teclas}}" + "{count,plural, =1{# acceso directo}other{# accesos directos}}" "%1$s, %2$s" "Widgets" "Buscar" diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index fabe73c868..b2d2654a53 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -164,12 +164,12 @@ "મનગમતી ઍપ" "ઑફિસની ઍપ" "ઑફિસની પ્રોફાઇલ" - "ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT વ્યવસ્થાપક તેમને જોઈ શકે છે" + "ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT ઍડમિન તેમને જોઈ શકે છે" "સમજાઈ ગયું" - "ઑફિસ માટેની ઍપ થોભાવવામાં આવેલ છે" + "ઑફિસ માટેની ઍપ થોભાવવામાં આવી છે" "ઑફિસ માટેની તમારી ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી" "ઑફિસ માટેની ઍપ બંધ છે. ઑફિસ માટેની તમારી ઍપ તમને નોટિફિકેશન મોકલી શકતી નથી, તમારી બૅટરી વાપરી શકતી નથી કે તમારું સ્થાન ઍક્સેસ કરી શકતી નથી" - "ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT વ્યવસ્થાપક તેમને જોઈ શકે છે" + "ઑફિસની ઍપને બૅજ આપેલા હોય છે અને તમારા IT ઍડમિન તેમને જોઈ શકે છે" "સમજાઈ ગયું" "ઑફિસ માટેની ઍપ બંધ કરો" "ઑફિસ માટેની ઍપ ચાલુ કરો" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 9f216968cc..0aa3f11479 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -32,7 +32,7 @@ "פיצול שמאלה" "פיצול ימינה" "‏פרטים על האפליקציה %1$s" - "כדי להעביר ווידג\'ט למקום אחר יש לגעת ולא להרפות." + "להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה." "כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות." "%1$d × %2$d" "‏רוחב %1$d על גובה %2$d" @@ -161,7 +161,7 @@ "סגירה" "סגירה" "ההתראה נסגרה" - "אישיות" + "אישי" "עבודה" "פרופיל עבודה" "‏האפליקציות לעבודה מתויגות ומוצגות למנהל ה-IT" @@ -171,7 +171,7 @@ "האפליקציות לעבודה מושבתות. האפליקציות לא יכולות לשלוח לך התראות, להשתמש בסוללה או לגשת למיקום שלך" "‏האפליקציות לעבודה מתויגות ומוצגות למנהל ה-IT" "הבנתי" - "כיבוי של אפליקציות לעבודה" + "השבתה של אפליקציות לעבודה" "הפעלה של אפליקציות לעבודה" "סינון" "הפעולה נכשלה: %1$s" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 8ce6c7341a..416f2042d9 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -164,7 +164,7 @@ "Personlig" "Jobb" "Jobbprofil" - "Jobbapper er merket og synlige for IT-administratoren din" + "Jobbapper er merket og synlige for IT-administratoren" "Greit" "Jobbapper er satt på pause" "Jobbapper kan ikke sende deg varsler, bruke batteriet eller få tilgang til posisjonen din" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 5553e8c97a..6b5fe2bba0 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -47,7 +47,7 @@ "Претражите" "Обришите текст из оквира за претрагу" "Виџети и пречице нису доступни" - "Није пронађен ниједан виџет или пречица" + "Није пронађен ниједан виџет ни пречица" "Лично" "Посао" "Конверзације" diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 4386f4196c..90869c2965 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -207,6 +207,13 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch return getView(activity, type, true /* mustBeOpen */); } + /** + * Returns whether there is at least one view of the given type where {@link #isOpen()} == true. + */ + public static boolean hasOpenView(ActivityContext activity, @FloatingViewType int type) { + return getOpenView(activity, type) != null; + } + /** * Returns a view matching FloatingViewType, and {@link #isOpen()} may be false (if animating * closed). diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b6a05b02d4..4b42ecbae0 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -42,7 +42,6 @@ import static com.android.launcher3.LauncherState.NO_SCALE; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions; -import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD; import static com.android.launcher3.logging.StatsLogManager.EventEnum; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; @@ -65,7 +64,6 @@ import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.app.Notification; @@ -109,7 +107,7 @@ import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.view.animation.OvershootInterpolator; @@ -130,7 +128,6 @@ import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.BaseAllAppsContainerView; import com.android.launcher3.allapps.DiscoveryBounce; -import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; @@ -186,8 +183,6 @@ import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; -import com.android.launcher3.util.MultiValueAlpha; -import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; @@ -341,6 +336,7 @@ public class Launcher extends StatefulActivity private Runnable mOnDeferredActivityLaunchCallback; private ViewOnDrawExecutor mPendingExecutor; + private OnPreDrawListener mOnInitialBindListener; private LauncherModel mModel; private ModelWriter mModelWriter; @@ -503,11 +499,10 @@ public class Launcher extends StatefulActivity if (!mModel.addCallbacksAndLoad(this)) { if (!internalStateHandled) { - Log.d(BAD_STATE, "Launcher onCreate not binding sync, setting DragLayer alpha " - + "ALPHA_INDEX_LAUNCHER_LOAD to 0"); - // If we are not binding synchronously, show a fade in animation when - // the first page bind completes. - mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0); + Log.d(BAD_STATE, "Launcher onCreate not binding sync, prevent drawing"); + // If we are not binding synchronously, pause drawing until initial bind complete, + // so that the system could continue to show the device loading prompt + mOnInitialBindListener = Boolean.FALSE::booleanValue; } } @@ -515,25 +510,9 @@ public class Launcher extends StatefulActivity setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); setContentView(getRootView()); - getRootView().getViewTreeObserver().addOnPreDrawListener( - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - // Checks the status of fade in animation. - final AlphaProperty property = - mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD); - if (property.getValue() == 0) { - Log.d(BAD_STATE, "Launcher onPreDraw ALPHA_INDEX_LAUNCHER_LOAD not" - + " started yet, cancelling draw."); - // Animation haven't started yet; suspend. - return false; - } else { - // The animation is started; start drawing. - getRootView().getViewTreeObserver().removeOnPreDrawListener(this); - return true; - } - } - }); + if (mOnInitialBindListener != null) { + getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener); + } getRootView().dispatchInsets(); // Listen for broadcasts @@ -2692,36 +2671,12 @@ public class Launcher extends StatefulActivity AllAppsStore.DEFER_UPDATES_NEXT_DRAW)); } - AlphaProperty property = mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD); - if (property.getValue() < 1) { - ObjectAnimator anim = ObjectAnimator.ofFloat(property, MultiValueAlpha.VALUE, 1); - - Log.d(BAD_STATE, "Launcher onInitialBindComplete toAlpha=" + 1); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - Log.d(BAD_STATE, "Launcher onInitialBindComplete onStart"); - } - - @Override - public void onAnimationCancel(Animator animation) { - float alpha = mDragLayer == null - ? -1 - : mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).getValue(); - Log.d(BAD_STATE, "Launcher onInitialBindComplete onCancel, alpha=" + alpha); - } - - @Override - public void onAnimationEnd(Animator animation) { - Log.d(BAD_STATE, "Launcher onInitialBindComplete onEnd"); - } - }); - - anim.addListener(AnimatorListeners.forEndCallback(executor::onLoadAnimationCompleted)); - anim.start(); - } else { - executor.onLoadAnimationCompleted(); + if (mOnInitialBindListener != null) { + getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener); + mOnInitialBindListener = null; } + + executor.onLoadAnimationCompleted(); executor.attachTo(this); if (Utilities.ATLEAST_S) { Trace.endAsyncSection(DISPLAY_WORKSPACE_TRACE_METHOD_NAME, diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index f5ac359af5..0a1d25ca2a 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1440,7 +1440,7 @@ public abstract class PagedView extends ViewGrou return Math.abs(velocity) > threshold; } - private void resetTouchState() { + protected void resetTouchState() { releaseVelocityTracker(); mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 8662d0067d..637a4189b8 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -44,6 +44,8 @@ import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.util.MultiAdditivePropertyFactory; +import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.views.ScrimView; @@ -76,20 +78,56 @@ public class AllAppsTransitionController } }; - public static final FloatProperty ALL_APPS_PULL_BACK_PROGRESS = - new FloatProperty("allAppsPullBackProgress") { + public static final FloatProperty ALL_APPS_PULL_BACK_TRANSLATION = + new FloatProperty("allAppsPullBackTranslation") { @Override public Float get(AllAppsTransitionController controller) { - return controller.mPullBackProgress; + if (controller.mIsTablet) { + return controller.mAppsView.getRecyclerViewContainer().getTranslationY(); + } else { + return controller.getAppsViewPullbackTranslationY().get( + controller.mAppsView); + } } @Override - public void setValue(AllAppsTransitionController controller, float progress) { - controller.setPullBackProgress(progress); + public void setValue(AllAppsTransitionController controller, float translation) { + if (controller.mIsTablet) { + controller.mAppsView.getRecyclerViewContainer().setTranslationY( + translation); + } else { + controller.getAppsViewPullbackTranslationY().set(controller.mAppsView, + translation); + } } }; + public static final FloatProperty ALL_APPS_PULL_BACK_ALPHA = + new FloatProperty("allAppsPullBackAlpha") { + + @Override + public Float get(AllAppsTransitionController controller) { + if (controller.mIsTablet) { + return controller.mAppsView.getRecyclerViewContainer().getAlpha(); + } else { + return controller.getAppsViewPullbackAlpha().getValue(); + } + } + + @Override + public void setValue(AllAppsTransitionController controller, float alpha) { + if (controller.mIsTablet) { + controller.mAppsView.getRecyclerViewContainer().setAlpha(alpha); + } else { + controller.getAppsViewPullbackAlpha().setValue(alpha); + } + } + }; + + private static final int INDEX_APPS_VIEW_PROGRESS = 0; + private static final int INDEX_APPS_VIEW_PULLBACK = 1; + private static final int APPS_VIEW_INDEX_COUNT = 2; private ActivityAllAppsContainerView mAppsView; @@ -104,18 +142,23 @@ public class AllAppsTransitionController // When {@link mProgress} is 1, all apps container is pulled down. private float mShiftRange; // changes depending on the orientation private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent - private float mPullBackProgress; // [0, 1], mShiftRange * mPullBackProgress = shiftCurrent private ScrimView mScrimView; - private View mPullBackView; + + private final MultiAdditivePropertyFactory + mAppsViewTranslationYPropertyFactory = new MultiAdditivePropertyFactory<>( + "appsViewTranslationY", View.TRANSLATION_Y); + private MultiValueAlpha mAppsViewAlpha; + + private boolean mIsTablet; public AllAppsTransitionController(Launcher l) { mLauncher = l; DeviceProfile dp = mLauncher.getDeviceProfile(); setShiftRange(dp.allAppsShiftRange); mProgress = 1f; - mPullBackProgress = 1f; mIsVerticalLayout = dp.isVerticalBarLayout(); + mIsTablet = dp.isTablet; mLauncher.addOnDeviceProfileChangeListener(this); } @@ -133,7 +176,7 @@ public class AllAppsTransitionController mLauncher.getWorkspace().getPageIndicator().setTranslationY(0); } - mPullBackView = dp.isTablet ? mAppsView.getRecyclerViewContainer() : mAppsView; + mIsTablet = dp.isTablet; } /** @@ -146,16 +189,27 @@ public class AllAppsTransitionController */ public void setProgress(float progress) { mProgress = progress; - mAppsView.setTranslationY(mProgress * mShiftRange); + getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange); } public float getProgress() { return mProgress; } - private void setPullBackProgress(float progress) { - mPullBackProgress = progress; - mPullBackView.setTranslationY(mPullBackProgress * mShiftRange); + private FloatProperty getAppsViewProgressTranslationY() { + return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PROGRESS); + } + + private FloatProperty getAppsViewPullbackTranslationY() { + return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PULLBACK); + } + + private MultiValueAlpha.AlphaProperty getAppsViewProgressAlpha() { + return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PROGRESS); + } + + private MultiValueAlpha.AlphaProperty getAppsViewPullbackAlpha() { + return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PULLBACK); } /** @@ -164,8 +218,6 @@ public class AllAppsTransitionController */ @Override public void setState(LauncherState state) { - // Always reset pull back progress when switching states. - setPullBackProgress(0f); setProgress(state.getVerticalProgress(mLauncher)); setAlphas(state, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER); onProgressAnimationEnd(); @@ -180,10 +232,13 @@ public class AllAppsTransitionController StateAnimationConfig config, PendingAnimation builder) { if (NORMAL.equals(toState) && mLauncher.isInState(ALL_APPS)) { UiThreadHelper.hideKeyboardAsync(mLauncher, mLauncher.getAppsView().getWindowToken()); + builder.addEndListener(success -> { + // Reset pull back progress and alpha after switching states. + ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f); + ALL_APPS_PULL_BACK_ALPHA.set(this, 1f); + }); } - // Always reset pull back progress when switching states. - setPullBackProgress(0f); float targetProgress = toState.getVerticalProgress(mLauncher); if (Float.compare(mProgress, targetProgress) == 0) { setAlphas(toState, config, builder); @@ -222,7 +277,8 @@ public class AllAppsTransitionController boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0; Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); - setter.setViewAlpha(mAppsView, hasAllAppsContent ? 1 : 0, allAppsFade); + setter.setFloat(getAppsViewProgressAlpha(), MultiValueAlpha.VALUE, + hasAllAppsContent ? 1 : 0, allAppsFade); boolean shouldProtectHeader = ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS; @@ -245,8 +301,8 @@ public class AllAppsTransitionController | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } mAppsView.setScrimView(scrimView); - mPullBackView = mLauncher.getDeviceProfile().isTablet - ? mAppsView.getRecyclerViewContainer() : mAppsView; + mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT); + mAppsViewAlpha.setUpdateVisibility(true); } /** diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 14e10918b6..8eeca7d6d8 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -65,9 +65,7 @@ import java.util.ArrayList; public class DragLayer extends BaseDragLayer { public static final int ALPHA_INDEX_OVERLAY = 0; - public static final int ALPHA_INDEX_LAUNCHER_LOAD = 1; - public static final int ALPHA_INDEX_TRANSITIONS = 2; - private static final int ALPHA_CHANNEL_COUNT = 3; + private static final int ALPHA_CHANNEL_COUNT = 1; public static final int ANIMATION_END_DISAPPEAR = 0; public static final int ANIMATION_END_REMAIN_VISIBLE = 2; diff --git a/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java new file mode 100644 index 0000000000..50f7027407 --- /dev/null +++ b/src/com/android/launcher3/util/MultiAdditivePropertyFactory.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.util; + +import android.util.ArrayMap; +import android.util.FloatProperty; +import android.util.Log; +import android.util.Property; +import android.view.View; + +/** + * Allows to combine multiple values set by several sources. + * + * The various sources are meant to use [set], providing different `setterIndex` params. When it is + * not set, 0 is used. This is meant to cover the case multiple animations are going on at the same + * time. + * + * This class behaves similarly to [MultiValueAlpha], but is meant to be more abstract and reusable. + * It sets the addition of all values. + * + * @param Type where to apply the property. + */ +public class MultiAdditivePropertyFactory { + + private static final boolean DEBUG = false; + private static final String TAG = "MultiAdditivePropertyFactory"; + private final String mName; + private final ArrayMap mProperties = + new ArrayMap<>(); + + // This is an optimization for cases when set is called repeatedly with the same setterIndex. + private float mAggregationOfOthers = 0f; + private Integer mLastIndexSet = -1; + private final Property mProperty; + + public MultiAdditivePropertyFactory(String name, Property property) { + mName = name; + mProperty = property; + } + + /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */ + public MultiAdditiveProperty get(Integer index) { + return mProperties.computeIfAbsent(index, + (k) -> new MultiAdditiveProperty(index, mName + "_" + index)); + } + + /** + * Each [setValue] will be aggregated with the other properties values created by the + * corresponding factory. + */ + class MultiAdditiveProperty extends FloatProperty { + private final int mInx; + private float mValue = 0f; + + MultiAdditiveProperty(int inx, String name) { + super(name); + mInx = inx; + } + + @Override + public void setValue(T obj, float newValue) { + if (mLastIndexSet != mInx) { + mAggregationOfOthers = 0f; + mProperties.forEach((key, property) -> { + if (key != mInx) { + mAggregationOfOthers += property.mValue; + } + }); + mLastIndexSet = mInx; + } + float lastAggregatedValue = mAggregationOfOthers + newValue; + mValue = newValue; + apply(obj, lastAggregatedValue); + + if (DEBUG) { + Log.d(TAG, "name=" + mName + + " newValue=" + newValue + " mInx=" + mInx + + " aggregated=" + lastAggregatedValue + " others= " + mProperties); + } + } + + @Override + public Float get(T view) { + // The scale of the view should match mLastAggregatedValue. Still, if it has been + // changed without using this property, it can differ. As this get method is usually + // used to set the starting point on an animation, this would result in some jumps + // when the view scale is different than the last aggregated value. To stay on the + // safe side, let's return the real view scale. + return mProperty.get(view); + } + + @Override + public String toString() { + return String.valueOf(mValue); + } + } + + protected void apply(View view, float value) { + mProperty.set(view, value); + } +} diff --git a/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt new file mode 100644 index 0000000000..309d055bad --- /dev/null +++ b/tests/src/com/android/launcher3/util/MultiAdditivePropertyTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.util + +import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +/** Unit tests for [MultiAdditivePropertyFactory] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class MultiAdditivePropertyTest { + + private val received = mutableListOf() + + private val factory = + object : MultiAdditivePropertyFactory("Test", View.TRANSLATION_X) { + override fun apply(obj: View?, value: Float) { + received.add(value) + } + } + + private val p1 = factory.get(1) + private val p2 = factory.get(2) + private val p3 = factory.get(3) + + @Test + fun set_sameIndexes_allApplied() { + val v1 = 50f + val v2 = 100f + p1.set(null, v1) + p1.set(null, v1) + p1.set(null, v2) + + assertThat(received).containsExactly(v1, v1, v2) + } + + @Test + fun set_differentIndexes_aggregationApplied() { + val v1 = 50f + val v2 = 100f + val v3 = 150f + p1.set(null, v1) + p2.set(null, v2) + p3.set(null, v3) + + assertThat(received).containsExactly(v1, v1 + v2, v1 + v2 + v3) + } +} diff --git a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt index 6099987172..7d92214d9b 100644 --- a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt +++ b/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.launcher3.util import android.view.View