diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 224c05e89e..15db49cf7a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -106,6 +106,10 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private static final String NAV_BUTTONS_SEPARATE_WINDOW_TITLE = "Taskbar Nav Buttons"; + public static final int ALPHA_INDEX_IMMERSIVE_MODE = 0; + public static final int ALPHA_INDEX_KEYGUARD_OR_DISABLE = 1; + private static final int NUM_ALPHA_CHANNELS = 2; + private final ArrayList mPropertyHolders = new ArrayList<>(); private final ArrayList mAllButtons = new ArrayList<>(); private int mState; @@ -140,6 +144,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private int mSysuiStateFlags; private View mBackButton; private View mHomeButton; + private MultiValueAlpha mBackButtonAlpha; + private MultiValueAlpha mHomeButtonAlpha; private FloatingRotationButton mFloatingRotationButton; // Variables for moving nav buttons to a separate window above IME @@ -180,8 +186,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mControllers.taskbarViewController.getTaskbarIconAlpha() .getProperty(ALPHA_INDEX_KEYGUARD), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 - && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0, - MultiValueAlpha.VALUE, 1, 0)); + && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0)); mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController .getKeyguardBgTaskbar(), @@ -347,7 +352,10 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK, mNavButtonContainer, mControllers.navButtonController, R.id.back); - mPropertyHolders.add(new StatePropertyHolder(mBackButton, + mBackButtonAlpha = new MultiValueAlpha(mBackButton, NUM_ALPHA_CHANNELS); + mBackButtonAlpha.setUpdateVisibility(true); + mPropertyHolders.add(new StatePropertyHolder( + mBackButtonAlpha.getProperty(ALPHA_INDEX_KEYGUARD_OR_DISABLE), flags -> { // Show only if not disabled, and if not on the keyguard or otherwise only when // the bouncer or a lockscreen app is showing above the keyguard @@ -373,7 +381,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT // home and recents buttons mHomeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer, navButtonController, R.id.home); - mPropertyHolders.add(new StatePropertyHolder(mHomeButton, + mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS); + mHomeButtonAlpha.setUpdateVisibility(true); + mPropertyHolders.add( + new StatePropertyHolder(mHomeButtonAlpha.getProperty( + ALPHA_INDEX_KEYGUARD_OR_DISABLE), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_HOME) == 0)); View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS, @@ -486,6 +498,20 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT } } + /** + * Returns multi-value alpha controller for back button. + */ + public MultiValueAlpha getBackButtonAlpha() { + return mBackButtonAlpha; + } + + /** + * Returns multi-value alpha controller for home button. + */ + public MultiValueAlpha getHomeButtonAlpha() { + return mHomeButtonAlpha; + } + /** Use to set the translationY for the all nav+contextual buttons */ public AnimatedFloat getTaskbarNavButtonTranslationY() { return mTaskbarNavButtonTranslationY; @@ -778,6 +804,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mAnimator.addListener(new AlphaUpdateListener(view)); } + StatePropertyHolder(MultiValueAlpha.AlphaProperty alphaProperty, + IntPredicate enableCondition) { + this(alphaProperty, enableCondition, MultiValueAlpha.VALUE, 1, 0); + } + StatePropertyHolder(T target, IntPredicate enabledCondition, Property property, float enabledValue, float disabledValue) { mEnableCondition = enabledCondition; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index e37bd21a68..6a59bc2a2d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -188,7 +188,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ new TaskbarStashController(this), new TaskbarEduController(this), new TaskbarAutohideSuspendController(this), - new TaskbarPopupController(this)); + new TaskbarPopupController(this), + new TaskbarForceVisibleImmersiveController(this)); } public void init(TaskbarSharedState sharedState) { @@ -417,6 +418,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags, fromInit); mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags); + mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index f4916698d9..8364137a82 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -47,6 +47,7 @@ public class TaskbarControllers { public final TaskbarEduController taskbarEduController; public final TaskbarAutohideSuspendController taskbarAutohideSuspendController; public final TaskbarPopupController taskbarPopupController; + public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @@ -70,7 +71,8 @@ public class TaskbarControllers { TaskbarStashController taskbarStashController, TaskbarEduController taskbarEduController, TaskbarAutohideSuspendController taskbarAutoHideSuspendController, - TaskbarPopupController taskbarPopupController) { + TaskbarPopupController taskbarPopupController, + TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -86,6 +88,7 @@ public class TaskbarControllers { this.taskbarEduController = taskbarEduController; this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController; this.taskbarPopupController = taskbarPopupController; + this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; } /** @@ -108,6 +111,7 @@ public class TaskbarControllers { taskbarStashController.init(this, sharedState); taskbarEduController.init(this); taskbarPopupController.init(this); + taskbarForceVisibleImmersiveController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, @@ -142,6 +146,7 @@ public class TaskbarControllers { stashedHandleViewController.onDestroy(); taskbarAutohideSuspendController.onDestroy(); taskbarPopupController.onDestroy(); + taskbarForceVisibleImmersiveController.onDestroy(); mControllersToLog = null; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index df004ef6e4..4a806650a5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -34,7 +34,6 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.R; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; import com.android.systemui.shared.system.ViewTreeObserverWrapper; import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo; @@ -105,7 +104,7 @@ public class TaskbarDragLayer extends BaseDragLayer { @Override public void recreateControllers() { - mControllers = new TouchController[] {mActivity.getDragController()}; + mControllers = mControllerCallbacks.getTouchControllers(); } private void onComputeTaskbarInsets(InsetsInfo insetsInfo) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index fa409923c4..1bd76b99bb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -26,6 +26,7 @@ import android.graphics.Rect; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.R; import com.android.launcher3.anim.AlphaUpdateListener; +import com.android.launcher3.util.TouchController; import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo; @@ -181,7 +182,8 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } else if (mControllers.taskbarViewController.areIconsVisible() - || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null) { + || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null + || mActivity.isNavBarKidsModeActive()) { // Taskbar has some touchable elements, take over the full taskbar area insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen() ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT); @@ -217,5 +219,13 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa public int getTaskbarBackgroundHeight() { return mActivity.getDeviceProfile().taskbarSize; } + + /** + * Returns touch controllers. + */ + public TouchController[] getTouchControllers() { + return new TouchController[]{mActivity.getDragController(), + mControllers.taskbarForceVisibleImmersiveController}; + } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java new file mode 100644 index 0000000000..66a927fdcc --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.taskbar; + +import static com.android.launcher3.taskbar.NavbarButtonsViewController.ALPHA_INDEX_IMMERSIVE_MODE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IMMERSIVE_MODE; + +import android.os.Handler; +import android.os.Looper; +import android.view.MotionEvent; + +import com.android.launcher3.util.MultiValueAlpha; +import com.android.launcher3.util.TouchController; +import com.android.quickstep.AnimatedFloat; + +import java.util.Optional; +import java.util.function.Consumer; + +/** + * Controller for taskbar when force visible in immersive mode is set. + */ +public class TaskbarForceVisibleImmersiveController implements TouchController { + private static final int NAV_BAR_ICONS_DIM_ANIMATION_START_DELAY_MS = 4500; + private static final int NAV_BAR_ICONS_DIM_ANIMATION_DURATION_MS = 500; + private static final int NAV_BAR_ICONS_UNDIM_ANIMATION_DURATION_MS = 250; + private static final float NAV_BAR_ICONS_DIM_PCT = 0.15f; + private static final float NAV_BAR_ICONS_UNDIM_PCT = 1f; + + private final TaskbarActivityContext mContext; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final Runnable mDimmingRunnable = this::dimIcons; + private final Runnable mUndimmingRunnable = this::undimIcons; + private final AnimatedFloat mIconAlphaForDimming = new AnimatedFloat( + this::updateIconDimmingAlpha); + private final Consumer mImmersiveModeAlphaUpdater = alpha -> alpha.getProperty( + ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value); + + // Initialized in init. + private TaskbarControllers mControllers; + private boolean mIsImmersiveMode; + + public TaskbarForceVisibleImmersiveController(TaskbarActivityContext context) { + mContext = context; + } + + /** + * Initialize controllers. + */ + public void init(TaskbarControllers controllers) { + mControllers = controllers; + } + + /** Update values tracked via sysui flags. */ + public void updateSysuiFlags(int sysuiFlags) { + mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_IMMERSIVE_MODE) != 0; + if (mContext.isNavBarKidsModeActive()) { + if (mIsImmersiveMode) { + startIconDimming(); + } else { + startIconUndimming(); + } + } + } + + /** Clean up animations. */ + public void onDestroy() { + startIconUndimming(); + } + + private void startIconUndimming() { + mHandler.removeCallbacks(mDimmingRunnable); + mHandler.removeCallbacks(mUndimmingRunnable); + mHandler.post(mUndimmingRunnable); + } + + private void undimIcons() { + mIconAlphaForDimming.animateToValue(NAV_BAR_ICONS_UNDIM_PCT).setDuration( + NAV_BAR_ICONS_UNDIM_ANIMATION_DURATION_MS).start(); + } + + private void startIconDimming() { + mHandler.removeCallbacks(mDimmingRunnable); + mHandler.postDelayed(mDimmingRunnable, NAV_BAR_ICONS_DIM_ANIMATION_START_DELAY_MS); + } + + private void dimIcons() { + mIconAlphaForDimming.animateToValue(NAV_BAR_ICONS_DIM_PCT).setDuration( + NAV_BAR_ICONS_DIM_ANIMATION_DURATION_MS).start(); + } + + /** + * Returns whether the taskbar is always visible in immersive mode. + */ + private boolean isNavbarShownInImmersiveMode() { + return mIsImmersiveMode && mContext.isNavBarKidsModeActive(); + } + + private void updateIconDimmingAlpha() { + getBackButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater); + getHomeButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater); + } + + private Optional getBackButtonAlphaOptional() { + if (mControllers == null || mControllers.navbarButtonsViewController == null) { + return Optional.empty(); + } + return Optional.ofNullable(mControllers.navbarButtonsViewController.getBackButtonAlpha()); + } + + private Optional getHomeButtonAlphaOptional() { + if (mControllers == null || mControllers.navbarButtonsViewController == null) { + return Optional.empty(); + } + return Optional.ofNullable(mControllers.navbarButtonsViewController.getHomeButtonAlpha()); + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (!isNavbarShownInImmersiveMode() + || mControllers.taskbarStashController.supportsManualStashing()) { + return false; + } + return onControllerTouchEvent(ev); + } + + @Override + public boolean onControllerTouchEvent(MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + startIconUndimming(); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + startIconDimming(); + break; + } + return false; + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 748557baeb..014e1727cf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -197,7 +197,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Returns whether the user can manually stash the taskbar based on the current device state. */ - private boolean supportsManualStashing() { + protected boolean supportsManualStashing() { return supportsVisualStashing() && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || supportsStashingForTests()); } diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java index 6a7d066cd8..6c7a885a1f 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java @@ -98,6 +98,15 @@ public class AnimatedFloat { } } + /** + * Starts the animation. + */ + public void startAnimation() { + if (mValueAnimator != null) { + mValueAnimator.start(); + } + } + public void cancelAnimation() { if (mValueAnimator != null) { mValueAnimator.cancel();