/* * Copyright (C) 2021 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 android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.graphics.Rect; import android.graphics.RectF; import android.view.MotionEvent; import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.states.StateAnimationConfig; /** * A data source which integrates with a Launcher instance * TODO: Rename to have Launcher prefix */ public class TaskbarController extends TaskbarUIController { private final BaseQuickstepLauncher mLauncher; private final TaskbarStateHandler mTaskbarStateHandler; private final TaskbarAnimationController mTaskbarAnimationController; private final TaskbarHotseatController mHotseatController; private final TaskbarActivityContext mContext; final TaskbarContainerView mTaskbarContainerView; final TaskbarView mTaskbarView; private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; public TaskbarController(BaseQuickstepLauncher launcher, TaskbarActivityContext context) { mContext = context; mTaskbarContainerView = context.getDragLayer(); mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); mLauncher = launcher; mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); mTaskbarAnimationController = new TaskbarAnimationController(mLauncher, createTaskbarAnimationControllerCallbacks()); mHotseatController = new TaskbarHotseatController( mLauncher, mTaskbarView::updateHotseatItems); } @Override protected void onCreate() { mTaskbarStateHandler.setAnimationController(mTaskbarAnimationController); mTaskbarAnimationController.init(); mHotseatController.init(); setTaskbarViewVisible(!mLauncher.hasBeenResumed()); alignRealHotseatWithTaskbar(); mLauncher.setTaskbarController(this); } @Override protected void onDestroy() { if (mAnimator != null) { // End this first, in case it relies on properties that are about to be cleaned up. mAnimator.end(); } mTaskbarStateHandler.setAnimationController(null); mTaskbarAnimationController.cleanup(); mHotseatController.cleanup(); setTaskbarViewVisible(true); mLauncher.getHotseat().setIconsAlpha(1f); mLauncher.setTaskbarController(null); } @Override protected boolean isTaskbarTouchable() { return !mIsAnimatingToLauncher; } private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() { return new TaskbarAnimationControllerCallbacks() { @Override public void updateTaskbarBackgroundAlpha(float alpha) { mTaskbarContainerView.setTaskbarBackgroundAlpha(alpha); } @Override public void updateTaskbarVisibilityAlpha(float alpha) { mTaskbarView.setAlpha(alpha); } @Override public void updateImeBarVisibilityAlpha(float alpha) { mTaskbarContainerView.updateImeBarVisibilityAlpha(alpha); } @Override public void updateTaskbarScale(float scale) { mTaskbarView.setScaleX(scale); mTaskbarView.setScaleY(scale); } @Override public void updateTaskbarTranslationY(float translationY) { if (translationY < 0) { // Resize to accommodate the max translation we'll reach. mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize + mLauncher.getHotseat().getTaskbarOffsetY()); } else { mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize); } mTaskbarView.setTranslationY(translationY); } }; } /** * Should be called from onResume() and onPause(), and animates the Taskbar accordingly. */ public void onLauncherResumedOrPaused(boolean isResumed) { long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION; if (mAnimator != null) { mAnimator.cancel(); } if (isResumed) { mAnimator = createAnimToLauncher(null, duration); } else { mAnimator = createAnimToApp(duration); } mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mAnimator = null; } }); mAnimator.start(); } /** * Create Taskbar animation when going from an app to Launcher. * @param toState If known, the state we will end up in when reaching Launcher. */ public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) { PendingAnimation anim = new PendingAnimation(duration); anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration)); if (toState != null) { mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim); } anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = true; mTaskbarView.setHolesAllowedInLayout(true); mTaskbarView.updateHotseatItemsVisibility(); } @Override public void onAnimationEnd(Animator animation) { mIsAnimatingToLauncher = false; setTaskbarViewVisible(false); } }); return anim.buildAnim(); } private Animator createAnimToApp(long duration) { PendingAnimation anim = new PendingAnimation(duration); anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration)); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mTaskbarView.updateHotseatItemsVisibility(); setTaskbarViewVisible(true); } @Override public void onAnimationEnd(Animator animation) { mTaskbarView.setHolesAllowedInLayout(false); } }); return anim.buildAnim(); } @Override protected void onImeVisible(TaskbarContainerView containerView, boolean isVisible) { mTaskbarAnimationController.animateToVisibilityForIme(isVisible ? 0 : 1); } /** * Should be called when one or more items in the Hotseat have changed. */ public void onHotseatUpdated() { mHotseatController.onHotseatUpdated(); } /** * @param ev MotionEvent in screen coordinates. * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. */ public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { return mTaskbarView.isEventOverAnyItem(ev); } public boolean isDraggingItem() { return mTaskbarView.isDraggingItem(); } /** * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat. */ @Override public void alignRealHotseatWithTaskbar() { Rect hotseatBounds = new Rect(); DeviceProfile grid = mLauncher.getDeviceProfile(); int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize; int taskbarOffset = mLauncher.getHotseat().getTaskbarOffsetY(); int hotseatTopDiff = hotseatHeight - grid.taskbarSize - taskbarOffset; int hotseatBottomDiff = taskbarOffset; RectF hotseatBoundsF = mTaskbarView.getHotseatBounds(); Utilities.scaleRectFAboutPivot(hotseatBoundsF, getTaskbarScaleOnHome(), mTaskbarView.getPivotX(), mTaskbarView.getPivotY()); hotseatBoundsF.round(hotseatBounds); mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff, mTaskbarView.getWidth() - hotseatBounds.right, mTaskbarView.getHeight() - hotseatBounds.bottom + hotseatBottomDiff); } /** * Returns the ratio of the taskbar icon size on home vs in an app. */ public float getTaskbarScaleOnHome() { DeviceProfile inAppDp = mContext.getDeviceProfile(); DeviceProfile onHomeDp = mLauncher.getDeviceProfile(); return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx; } void setTaskbarViewVisible(boolean isVisible) { mTaskbarView.setIconsVisibility(isVisible); mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f); } /** * Contains methods that TaskbarAnimationController can call to interface with * TaskbarController. */ protected interface TaskbarAnimationControllerCallbacks { void updateTaskbarBackgroundAlpha(float alpha); void updateTaskbarVisibilityAlpha(float alpha); void updateImeBarVisibilityAlpha(float alpha); void updateTaskbarScale(float scale); void updateTaskbarTranslationY(float translationY); } }