blob: c2d107c22dc56ff37d86a742be165a4695616cab [file] [log] [blame]
/*
* 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 LauncherTaskbarUIController extends TaskbarUIController {
private final BaseQuickstepLauncher mLauncher;
private final TaskbarStateHandler mTaskbarStateHandler;
private final TaskbarAnimationController mTaskbarAnimationController;
private final TaskbarHotseatController mHotseatController;
private final TaskbarActivityContext mContext;
final TaskbarDragLayer mTaskbarDragLayer;
final TaskbarView mTaskbarView;
private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
public LauncherTaskbarUIController(
BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
mContext = context;
mTaskbarDragLayer = context.getDragLayer();
mTaskbarView = mTaskbarDragLayer.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.setTaskbarUIController(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.setTaskbarUIController(null);
}
@Override
protected boolean isTaskbarTouchable() {
return !mIsAnimatingToLauncher;
}
private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
return new TaskbarAnimationControllerCallbacks() {
@Override
public void updateTaskbarBackgroundAlpha(float alpha) {
mTaskbarDragLayer.setTaskbarBackgroundAlpha(alpha);
}
@Override
public void updateTaskbarVisibilityAlpha(float alpha) {
mTaskbarView.setAlpha(alpha);
}
@Override
public void updateImeBarVisibilityAlpha(float alpha) {
mTaskbarDragLayer.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(TaskbarDragLayer 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);
}
}