diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml index 6e1aa1e3d5..87649f752e 100644 --- a/quickstep/res/layout/taskbar_divider.xml +++ b/quickstep/res/layout/taskbar_divider.xml @@ -18,6 +18,4 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/taskbar_divider_thickness" android:layout_height="@dimen/taskbar_divider_height" - android:layout_marginStart="@dimen/taskbar_icon_spacing" - android:layout_marginEnd="@dimen/taskbar_icon_spacing" android:background="@color/taskbar_divider" /> \ No newline at end of file diff --git a/quickstep/res/layout/taskbar_view.xml b/quickstep/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..34a88ea6a2 --- /dev/null +++ b/quickstep/res/layout/taskbar_view.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index c4becf105f..9ab49cebfa 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -46,6 +46,7 @@ import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarController; import com.android.launcher3.taskbar.TaskbarStateHandler; +import com.android.launcher3.taskbar.TaskbarView; import com.android.launcher3.uioverrides.RecentsViewStateController; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.DisplayController; @@ -243,9 +244,10 @@ public abstract class BaseQuickstepLauncher extends Launcher mTaskbarController = null; } if (mDeviceProfile.isTaskbarPresent) { + TaskbarView taskbarViewOnHome = (TaskbarView) mHotseat.getTaskbarView(); TaskbarActivityContext taskbarActivityContext = new TaskbarActivityContext(this); mTaskbarController = new TaskbarController(this, - taskbarActivityContext.getTaskbarContainerView()); + taskbarActivityContext.getTaskbarContainerView(), taskbarViewOnHome); mTaskbarController.init(); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8312b82062..fc5e2c1740 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -54,10 +54,7 @@ public class TaskbarActivityContext extends ContextWrapper implements ActivityCo return mTaskbarContainerView; } - /** - * @return A LayoutInflater to use in this Context. Views inflated with this LayoutInflater will - * be able to access this TaskbarActivityContext via ActivityContext.lookupContext(). - */ + @Override public LayoutInflater getLayoutInflater() { return mLayoutInflater; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java index 528f43e699..5202d91684 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarContainerView.java @@ -84,7 +84,7 @@ public class TaskbarContainerView extends BaseDragLayer private ViewTreeObserverWrapper.OnComputeInsetsListener createTaskbarInsetsComputer() { return insetsInfo -> { if (getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD - || mTaskbarView.isDraggingItem()) { + || mTaskbarView.getVisibility() != VISIBLE || mTaskbarView.isDraggingItem()) { // We're invisible or dragging out of taskbar, let touches pass through us. insetsInfo.touchableRegion.setEmpty(); insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java index f652961629..abf6d54146 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java @@ -19,8 +19,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_TASKBAR; -import static com.android.launcher3.AbstractFloatingView.TYPE_REPLACE_TASKBAR_WITH_HOTSEAT; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT; @@ -43,7 +41,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Hotseat; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; @@ -54,6 +51,7 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -70,7 +68,8 @@ public class TaskbarController { private static final String WINDOW_TITLE = "Taskbar"; private final TaskbarContainerView mTaskbarContainerView; - private final TaskbarView mTaskbarView; + private final TaskbarView mTaskbarViewInApp; + private final TaskbarView mTaskbarViewOnHome; private final BaseQuickstepLauncher mLauncher; private final WindowManager mWindowManager; // Layout width and height of the Taskbar in the default state. @@ -91,14 +90,17 @@ public class TaskbarController { private @Nullable Animator mAnimator; private boolean mIsAnimatingToLauncher; + private boolean mIsAnimatingToApp; public TaskbarController(BaseQuickstepLauncher launcher, - TaskbarContainerView taskbarContainerView) { + TaskbarContainerView taskbarContainerView, TaskbarView taskbarViewOnHome) { mLauncher = launcher; mTaskbarContainerView = taskbarContainerView; mTaskbarContainerView.construct(createTaskbarContainerViewCallbacks()); - mTaskbarView = mTaskbarContainerView.findViewById(R.id.taskbar_view); - mTaskbarView.construct(createTaskbarViewCallbacks()); + mTaskbarViewInApp = mTaskbarContainerView.findViewById(R.id.taskbar_view); + mTaskbarViewInApp.construct(createTaskbarViewCallbacks()); + mTaskbarViewOnHome = taskbarViewOnHome; + mTaskbarViewOnHome.construct(createTaskbarViewCallbacks()); mWindowManager = mLauncher.getWindowManager(); mTaskbarSize = new Point(MATCH_PARENT, mLauncher.getDeviceProfile().taskbarSize); mTaskbarStateHandler = mLauncher.getTaskbarStateHandler(); @@ -115,12 +117,13 @@ public class TaskbarController { return new TaskbarVisibilityControllerCallbacks() { @Override public void updateTaskbarBackgroundAlpha(float alpha) { - mTaskbarView.setBackgroundAlpha(alpha); + mTaskbarViewInApp.setBackgroundAlpha(alpha); } @Override public void updateTaskbarVisibilityAlpha(float alpha) { mTaskbarContainerView.setAlpha(alpha); + mTaskbarViewOnHome.setAlpha(alpha); } }; } @@ -196,7 +199,7 @@ public class TaskbarController { public View.OnLongClickListener getItemOnLongClickListener() { return view -> { if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) { - alignRealHotseatWithTaskbar(); + // TODO: remove this path return mDragController.startWorkspaceDragOnLongClick(view); } else { return mDragController.startSystemDragOnLongClick(view); @@ -205,11 +208,24 @@ public class TaskbarController { } @Override - public int getEmptyHotseatViewVisibility() { + public int getEmptyHotseatViewVisibility(TaskbarView taskbarView) { // When on the home screen, we want the empty hotseat views to take up their full // space so that the others line up with the home screen hotseat. - return mLauncher.hasBeenResumed() || mIsAnimatingToLauncher - ? View.INVISIBLE : View.GONE; + boolean isOnHomeScreen = taskbarView == mTaskbarViewOnHome + || mLauncher.hasBeenResumed() || mIsAnimatingToLauncher; + return isOnHomeScreen ? View.INVISIBLE : View.GONE; + } + + @Override + public float getNonIconScale(TaskbarView taskbarView) { + return taskbarView == mTaskbarViewOnHome ? getTaskbarScaleOnHome() : 1f; + } + + @Override + public void onItemPositionsChanged(TaskbarView taskbarView) { + if (taskbarView == mTaskbarViewOnHome) { + alignRealHotseatWithTaskbar(); + } } }; } @@ -218,7 +234,7 @@ public class TaskbarController { return new TaskbarHotseatControllerCallbacks() { @Override public void updateHotseatItems(ItemInfo[] hotseatItemInfos) { - mTaskbarView.updateHotseatItems(hotseatItemInfos); + mTaskbarViewInApp.updateHotseatItems(hotseatItemInfos); mLatestLoadedHotseatItems = hotseatItemInfos; dedupeAndUpdateRecentItems(); } @@ -235,7 +251,8 @@ public class TaskbarController { @Override public void updateRecentTaskAtIndex(int taskIndex, Task task) { - mTaskbarView.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewInApp.updateRecentTaskAtIndex(taskIndex, task); + mTaskbarViewOnHome.updateRecentTaskAtIndex(taskIndex, task); } }; } @@ -244,16 +261,20 @@ public class TaskbarController { * Initializes the Taskbar, including adding it to the screen. */ public void init() { - mTaskbarView.init(mHotseatController.getNumHotseatIcons(), + mTaskbarViewInApp.init(mHotseatController.getNumHotseatIcons(), mRecentsController.getNumRecentIcons()); - mTaskbarContainerView.init(mTaskbarView); + mTaskbarViewOnHome.init(mHotseatController.getNumHotseatIcons(), + mRecentsController.getNumRecentIcons()); + mTaskbarContainerView.init(mTaskbarViewInApp); addToWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks()); mTaskbarVisibilityController.init(); mHotseatController.init(); mRecentsController.init(); - SCALE_PROPERTY.set(mTaskbarView, mLauncher.hasBeenResumed() ? getTaskbarScaleOnHome() : 1f); + SCALE_PROPERTY.set(mTaskbarViewInApp, mLauncher.hasBeenResumed() + ? getTaskbarScaleOnHome() : 1f); + updateWhichTaskbarViewIsVisible(); } private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() { @@ -274,7 +295,8 @@ public class TaskbarController { mAnimator.end(); } - mTaskbarView.cleanup(); + mTaskbarViewInApp.cleanup(); + mTaskbarViewOnHome.cleanup(); mTaskbarContainerView.cleanup(); removeFromWindowManager(); mTaskbarStateHandler.setTaskbarCallbacks(null); @@ -313,7 +335,7 @@ public class TaskbarController { TaskbarContainerView.LayoutParams taskbarLayoutParams = new TaskbarContainerView.LayoutParams(mTaskbarSize.x, mTaskbarSize.y); taskbarLayoutParams.gravity = gravity; - mTaskbarView.setLayoutParams(taskbarLayoutParams); + mTaskbarViewInApp.setLayoutParams(taskbarLayoutParams); mWindowManager.addView(mTaskbarContainerView, mWindowLayoutParams); } @@ -330,7 +352,6 @@ public class TaskbarController { mAnimator = createAnimToLauncher(null, duration); } else { mAnimator = createAnimToApp(duration); - replaceTaskbarWithHotseatOrViceVersa(); } mAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -351,36 +372,41 @@ public class TaskbarController { if (toState != null) { mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim); } - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), getTaskbarScaleOnHome(), LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = true; - mTaskbarView.updateHotseatItemsVisibility(); + mTaskbarViewInApp.updateHotseatItemsVisibility(); } @Override public void onAnimationEnd(Animator animation) { mIsAnimatingToLauncher = false; + updateWhichTaskbarViewIsVisible(); } }); - anim.addOnFrameCallback(this::alignRealHotseatWithTaskbar); - return anim.buildAnim(); } private Animator createAnimToApp(long duration) { PendingAnimation anim = new PendingAnimation(duration); anim.add(mTaskbarVisibilityController.createAnimToBackgroundAlpha(1, duration)); - anim.addFloat(mTaskbarView, SCALE_PROPERTY, mTaskbarView.getScaleX(), 1f, LINEAR); + anim.addFloat(mTaskbarViewInApp, SCALE_PROPERTY, mTaskbarViewInApp.getScaleX(), 1f, LINEAR); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mTaskbarView.updateHotseatItemsVisibility(); - setReplaceTaskbarWithHotseat(false); + mIsAnimatingToApp = true; + mTaskbarViewInApp.updateHotseatItemsVisibility(); + updateWhichTaskbarViewIsVisible(); + } + + @Override + public void onAnimationEnd(Animator animation) { + mIsAnimatingToApp = false; } }); return anim.buildAnim(); @@ -405,11 +431,11 @@ public class TaskbarController { * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. */ public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { - return mTaskbarView.isEventOverAnyItem(ev); + return mTaskbarViewInApp.isEventOverAnyItem(ev); } public boolean isDraggingItem() { - return mTaskbarView.isDraggingItem(); + return mTaskbarViewInApp.isDraggingItem() || mTaskbarViewOnHome.isDraggingItem(); } private void dedupeAndUpdateRecentItems() { @@ -454,7 +480,8 @@ public class TaskbarController { tasksArray[tasksArray.length - 1 - i] = task; } - mTaskbarView.updateRecentTasks(tasksArray); + mTaskbarViewInApp.updateRecentTasks(tasksArray); + mTaskbarViewOnHome.updateRecentTasks(tasksArray); mRecentsController.loadIconsForTasks(tasksArray); } @@ -475,10 +502,11 @@ public class TaskbarController { int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize; int hotseatTopDiff = hotseatHeight - grid.taskbarSize; - mTaskbarView.getHotseatBoundsAtScale(getTaskbarScaleOnHome()).roundOut(hotseatBounds); - mLauncher.getHotseat().setPadding(hotseatBounds.left, hotseatBounds.top + hotseatTopDiff, - mTaskbarView.getWidth() - hotseatBounds.right, - mTaskbarView.getHeight() - hotseatBounds.bottom); + mTaskbarViewOnHome.getHotseatBounds().roundOut(hotseatBounds); + mLauncher.getHotseat().setPadding(hotseatBounds.left, + hotseatBounds.top + hotseatTopDiff, + mTaskbarViewOnHome.getWidth() - hotseatBounds.right, + mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom); } /** @@ -486,36 +514,32 @@ public class TaskbarController { * show the real one instead. */ public void onLauncherDragLayerHierarchyChanged() { - replaceTaskbarWithHotseatOrViceVersa(); + // TODO: remove, as this is a no-op now } - private void replaceTaskbarWithHotseatOrViceVersa() { - boolean replaceTaskbarWithHotseat = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_REPLACE_TASKBAR_WITH_HOTSEAT) != null; - if (!mLauncher.hasBeenResumed()) { - replaceTaskbarWithHotseat = false; - } - setReplaceTaskbarWithHotseat(replaceTaskbarWithHotseat); - - boolean hideTaskbar = AbstractFloatingView.getTopOpenViewWithType(mLauncher, - TYPE_HIDE_TASKBAR) != null; - mTaskbarVisibilityController.animateToVisibilityForFloatingView(hideTaskbar ? 0f : 1f); - } - - private void setReplaceTaskbarWithHotseat(boolean replaceTaskbarWithHotseat) { - Hotseat hotseat = mLauncher.getHotseat(); - if (replaceTaskbarWithHotseat) { - alignRealHotseatWithTaskbar(); - hotseat.getReplaceTaskbarAlpha().setValue(1f); - mTaskbarView.setHotseatViewsHidden(true); + private void updateWhichTaskbarViewIsVisible() { + boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher + || mIsAnimatingToApp; + if (isInApp) { + mTaskbarViewInApp.setVisibility(View.VISIBLE); + mTaskbarViewOnHome.setVisibility(View.INVISIBLE); + mLauncher.getHotseat().setIconsAlpha(0); } else { - hotseat.getReplaceTaskbarAlpha().setValue(0f); - mTaskbarView.setHotseatViewsHidden(false); + mTaskbarViewInApp.setVisibility(View.INVISIBLE); + mTaskbarViewOnHome.setVisibility(View.VISIBLE); + mLauncher.getHotseat().setIconsAlpha(1); } } - private float getTaskbarScaleOnHome() { - return 1f / mTaskbarContainerView.getTaskbarActivityContext().getTaskbarIconScale(); + /** + * Returns the ratio of the taskbar icon size on home vs in an app. + */ + public float getTaskbarScaleOnHome() { + DeviceProfile inAppDp = mTaskbarContainerView.getTaskbarActivityContext() + .getDeviceProfile(); + DeviceProfile onHomeDp = ActivityContext.lookupContext(mTaskbarViewOnHome.getContext()) + .getDeviceProfile(); + return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx; } /** @@ -561,7 +585,10 @@ public class TaskbarController { protected interface TaskbarViewCallbacks { View.OnClickListener getItemOnClickListener(); View.OnLongClickListener getItemOnLongClickListener(); - int getEmptyHotseatViewVisibility(); + int getEmptyHotseatViewVisibility(TaskbarView taskbarView); + /** Returns how much to scale non-icon elements such as spacing and dividers. */ + float getNonIconScale(TaskbarView taskbarView); + void onItemPositionsChanged(TaskbarView taskbarView); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 1d762e9696..3567c17afa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -15,11 +15,14 @@ */ package com.android.launcher3.taskbar; +import android.animation.Animator; +import android.animation.AnimatorSet; import android.animation.LayoutTransition; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -36,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.folder.FolderIcon; @@ -48,20 +52,23 @@ import com.android.systemui.shared.recents.model.Task; /** * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps. */ -public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent { +public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable { private final ColorDrawable mBackgroundDrawable; - private final int mItemMarginLeftRight; + private final int mDividerWidth; + private final int mDividerHeight; private final int mIconTouchSize; private final boolean mIsRtl; private final int mTouchSlop; private final RectF mTempDelegateBounds = new RectF(); private final RectF mDelegateSlopBounds = new RectF(); private final int[] mTempOutLocation = new int[2]; - private final Matrix mTempMatrix = new Matrix(); // Initialized in TaskbarController constructor. private TaskbarController.TaskbarViewCallbacks mControllerCallbacks; + // Scale on elements that aren't icons. + private float mNonIconScale; + private int mItemMarginLeftRight; // Initialized in init(). private LayoutTransition mLayoutTransition; @@ -78,7 +85,6 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private boolean mIsDraggingItem; // Only non-null when the corresponding Folder is open. private @Nullable FolderIcon mLeaveBehindFolderIcon; - private boolean mIsHotseatHidden; public TaskbarView(@NonNull Context context) { this(context, null); @@ -99,7 +105,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa Resources resources = getResources(); mBackgroundDrawable = (ColorDrawable) getBackground(); - mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mDividerWidth = resources.getDimensionPixelSize(R.dimen.taskbar_divider_thickness); + mDividerHeight = resources.getDimensionPixelSize(R.dimen.taskbar_divider_height); mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size); mIsRtl = Utilities.isRtl(resources); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); @@ -107,11 +114,16 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa protected void construct(TaskbarController.TaskbarViewCallbacks taskbarViewCallbacks) { mControllerCallbacks = taskbarViewCallbacks; + mNonIconScale = mControllerCallbacks.getNonIconScale(this); + mItemMarginLeftRight = getResources().getDimensionPixelSize(R.dimen.taskbar_icon_spacing); + mItemMarginLeftRight = Math.round(mItemMarginLeftRight * mNonIconScale); } protected void init(int numHotseatIcons, int numRecentIcons) { mLayoutTransition = new LayoutTransition(); - setLayoutTransitionsEnabled(true); + addUpdateListenerForAllLayoutTransitions( + () -> mControllerCallbacks.onItemPositionsChanged(this)); + setLayoutTransition(mLayoutTransition); mHotseatStartIndex = 0; mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1; @@ -125,12 +137,30 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa updateRecentTasks(new Task[numRecentIcons]); } - private void setLayoutTransitionsEnabled(boolean enabled) { - setLayoutTransition(enabled ? mLayoutTransition : null); + private void addUpdateListenerForAllLayoutTransitions(Runnable onUpdate) { + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGE_DISAPPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.CHANGING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.APPEARING, onUpdate); + addUpdateListenerForLayoutTransition(LayoutTransition.DISAPPEARING, onUpdate); + } + + private void addUpdateListenerForLayoutTransition(int transitionType, Runnable onUpdate) { + Animator anim = mLayoutTransition.getAnimator(transitionType); + if (anim instanceof ValueAnimator) { + ((ValueAnimator) anim).addUpdateListener(valueAnimator -> onUpdate.run()); + } else { + AnimatorSet animSet = new AnimatorSet(); + ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1); + updateAnim.addUpdateListener(valueAnimator -> onUpdate.run()); + animSet.playTogether(anim, updateAnim); + mLayoutTransition.setAnimator(transitionType, animSet); + } } protected void cleanup() { removeAllViews(); + mHotseatRecentsDivider = null; } /** @@ -170,12 +200,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa if (hotseatView == null || hotseatView.getSourceLayoutResId() != expectedLayoutResId || needsReinflate) { removeView(hotseatView); - TaskbarActivityContext activityContext = - ActivityContext.lookupContext(getContext()); + ActivityContext activityContext = ActivityContext.lookupContext(getContext()); if (isFolder) { FolderInfo folderInfo = (FolderInfo) hotseatItemInfo; FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId, - activityContext, this, folderInfo); + ActivityContext.lookupContext(getContext()), this, folderInfo); folderIcon.setTextVisible(false); hotseatView = folderIcon; } else { @@ -216,22 +245,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } } - /** - * Hides or shows the hotseat items immediately (without layout transitions). - */ - protected void setHotseatViewsHidden(boolean hidden) { - mIsHotseatHidden = hidden; - setLayoutTransitionsEnabled(false); - updateHotseatItemsVisibility(); - setLayoutTransitionsEnabled(true); - } - private void updateHotseatItemVisibility(View hotseatView) { if (hotseatView.getTag() != null) { - hotseatView.setVisibility(mIsHotseatHidden ? INVISIBLE : VISIBLE); + hotseatView.setVisibility(VISIBLE); } else { int oldVisibility = hotseatView.getVisibility(); - int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(); + int newVisibility = mControllerCallbacks.getEmptyHotseatViewVisibility(this); hotseatView.setVisibility(newVisibility); if (oldVisibility == GONE && newVisibility != GONE) { // By default, the layout transition only runs when going to VISIBLE, @@ -243,7 +262,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa private View addDivider(int dividerIndex) { View divider = inflate(R.layout.taskbar_divider); - addView(divider, dividerIndex); + LayoutParams lp = new LayoutParams(mDividerWidth, mDividerHeight); + lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0); + divider.setScaleX(mNonIconScale); + divider.setScaleY(mNonIconScale); + addView(divider, dividerIndex, lp); return divider; } @@ -437,9 +460,9 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } /** - * @return The bounding box of where the hotseat elements will be when we reach the given scale. + * @return The bounding box of where the hotseat elements are relative to this TaskbarView. */ - protected RectF getHotseatBoundsAtScale(float taskbarViewScale) { + protected RectF getHotseatBounds() { View firstHotseatView = null, lastHotseatView = null; for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) { View child = getChildAt(i); @@ -455,14 +478,11 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } View leftmostHotseatView = !mIsRtl ? firstHotseatView : lastHotseatView; View rightmostHotseatView = !mIsRtl ? lastHotseatView : firstHotseatView; - RectF hotseatBounds = new RectF( + return new RectF( leftmostHotseatView.getLeft() - mItemMarginLeftRight, leftmostHotseatView.getTop(), rightmostHotseatView.getRight() + mItemMarginLeftRight, rightmostHotseatView.getBottom()); - mTempMatrix.setScale(taskbarViewScale, taskbarViewScale, getPivotX(), getPivotY()); - mTempMatrix.mapRect(hotseatBounds); - return hotseatBounds; } // FolderIconParent implemented methods. @@ -493,7 +513,12 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa } private View inflate(@LayoutRes int layoutResId) { - TaskbarActivityContext taskbarActivityContext = ActivityContext.lookupContext(getContext()); - return taskbarActivityContext.getLayoutInflater().inflate(layoutResId, this, false); + return ActivityContext.lookupContext(getContext()).getLayoutInflater() + .inflate(layoutResId, this, false); + } + + @Override + public void setInsets(Rect insets) { + // Ignore, we just implement Insettable to draw behind system insets. } } diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index ae644cd6fd..3faf72a006 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -112,20 +112,32 @@ public class StaggeredWorkspaceAnim { } // Set up springs for the hotseat and qsb. - ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0); + ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets(); if (grid.isVerticalBarLayout()) { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + 1, totalRows); } } else { - for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { - View child = hotseatChild.getChildAt(i); - addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows); + final int hotseatRow, qsbRow, taskbarRow; + if (grid.isTaskbarPresent) { + qsbRow = grid.inv.numRows + 1; + hotseatRow = grid.inv.numRows + 2; + } else { + hotseatRow = grid.inv.numRows + 1; + qsbRow = grid.inv.numRows + 2; + } + // Taskbar and hotseat overlap. + taskbarRow = hotseatRow; + + for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { + View child = hotseatIcons.getChildAt(i); + addStaggeredAnimationForView(child, hotseatRow, totalRows); } - addStaggeredAnimationForView(hotseat.getQsb(), grid.inv.numRows + 2, totalRows); + addStaggeredAnimationForView(hotseat.getQsb(), qsbRow, totalRows); + addStaggeredAnimationForView(hotseat.getTaskbarView(), taskbarRow, totalRows); } if (animateOverviewScrim) { diff --git a/res/layout/taskbar_view.xml b/res/layout/taskbar_view.xml new file mode 100644 index 0000000000..96ae43db4a --- /dev/null +++ b/res/layout/taskbar_view.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index af4a843b12..4049ed6882 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -29,8 +29,6 @@ import android.widget.FrameLayout; import androidx.annotation.Nullable; -import com.android.launcher3.util.MultiValueAlpha; - import java.util.function.Consumer; /** @@ -38,10 +36,6 @@ import java.util.function.Consumer; */ public class Hotseat extends CellLayout implements Insettable { - private static final int ALPHA_INDEX_STATE = 0; - private static final int ALPHA_INDEX_REPLACE_TASKBAR = 1; - private static final int NUM_ALPHA_CHANNELS = 2; - // Ratio of empty space, qsb should take up to appear visually centered. public static final float QSB_CENTER_FACTOR = .325f; @@ -52,10 +46,12 @@ public class Hotseat extends CellLayout implements Insettable { @Nullable private Consumer mOnVisibilityAggregatedCallback; - private final MultiValueAlpha mMultiValueAlpha; private final View mQsb; private final int mQsbHeight; + private final View mTaskbarView; + private final int mTaskbarViewHeight; + public Hotseat(Context context) { this(context, null); } @@ -66,12 +62,15 @@ public class Hotseat extends CellLayout implements Insettable { public Hotseat(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS, MultiValueAlpha.Mode.MAX); - mMultiValueAlpha.setUpdateVisibility(true); mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); mQsbHeight = mQsb.getLayoutParams().height; addView(mQsb); + + mTaskbarView = LayoutInflater.from(context).inflate(R.layout.taskbar_view, this, false); + mTaskbarViewHeight = mTaskbarView.getLayoutParams().height; + // We want taskbar in the back so its background applies to Hotseat as well. + addView(mTaskbarView, 0); } /** @@ -193,6 +192,8 @@ public class Hotseat extends CellLayout implements Insettable { int width = getShortcutsAndWidgets().getMeasuredWidth(); mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY)); + mTaskbarView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mTaskbarViewHeight, MeasureSpec.EXACTLY)); } @Override @@ -212,6 +213,13 @@ public class Hotseat extends CellLayout implements Insettable { - (dp.isTaskbarPresent ? dp.taskbarSize : dp.getInsets().bottom); int top = bottom - mQsbHeight; mQsb.layout(left, top, right, bottom); + + int taskbarWidth = mTaskbarView.getMeasuredWidth(); + left = (r - l - taskbarWidth) / 2; + right = left + taskbarWidth; + bottom = b - t; + top = bottom - mTaskbarViewHeight; + mTaskbarView.layout(left, top, right, bottom); } /** @@ -221,12 +229,11 @@ public class Hotseat extends CellLayout implements Insettable { return mWorkspace.getFirstMatch(new CellLayout[] { this }, itemOperator); } - public MultiValueAlpha.AlphaProperty getStateAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_STATE); - } - - public MultiValueAlpha.AlphaProperty getReplaceTaskbarAlpha() { - return mMultiValueAlpha.getProperty(ALPHA_INDEX_REPLACE_TASKBAR); + /** + * Sets the alpha value of just our ShortcutAndWidgetContainer. + */ + public void setIconsAlpha(float alpha) { + getShortcutsAndWidgets().setAlpha(alpha); } /** @@ -235,4 +242,11 @@ public class Hotseat extends CellLayout implements Insettable { public View getQsb() { return mQsb; } + + /** + * Returns the Taskbar inside hotseat + */ + public View getTaskbarView() { + return mTaskbarView; + } } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index e9a34953d5..0f8c6b9172 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -185,12 +185,7 @@ public abstract class LauncherState implements BaseState { } public int getVisibleElements(Launcher launcher) { - DeviceProfile deviceProfile = launcher.getDeviceProfile(); - int flags = WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; - if (!deviceProfile.isTaskbarPresent) { - flags |= HOTSEAT_ICONS; - } - return flags; + return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR; } /** diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 412754e211..cfcf0a0ced 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -54,7 +54,6 @@ import com.android.launcher3.graphics.SysUiScrim; import com.android.launcher3.graphics.WorkspaceDragScrim; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; -import com.android.launcher3.util.MultiValueAlpha; import com.android.systemui.plugins.ResourceProvider; /** @@ -135,8 +134,8 @@ public class WorkspaceStateTransitionAnimation { } float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; - propertySetter.setFloat(hotseat.getStateAlpha(), MultiValueAlpha.VALUE, - hotseatIconsAlpha, config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); + propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, + config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator)); float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0; propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, fadeInterpolator); diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index 505c6cea42..71aa4ac445 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -18,6 +18,7 @@ package com.android.launcher3.views; import android.content.Context; import android.content.ContextWrapper; import android.graphics.Rect; +import android.view.LayoutInflater; import android.view.View.AccessibilityDelegate; import com.android.launcher3.DeviceProfile; @@ -66,6 +67,18 @@ public interface ActivityContext { default void updateOpenFolderPosition(int[] inOutPosition, Rect bounds, int width, int height) { } + /** + * Returns a LayoutInflater that is cloned in this Context, so that Views inflated by it will + * have the same Context. (i.e. {@link #lookupContext(Context)} will find this ActivityContext.) + */ + default LayoutInflater getLayoutInflater() { + if (this instanceof Context) { + Context context = (Context) this; + return LayoutInflater.from(context).cloneInContext(context); + } + return null; + } + /** * The root view to support drag-and-drop and popup support. */ @@ -73,7 +86,10 @@ public interface ActivityContext { DeviceProfile getDeviceProfile(); - static T lookupContext(Context context) { + /** + * Returns the ActivityContext associated with the given Context. + */ + static T lookupContext(Context context) { if (context instanceof ActivityContext) { return (T) context; } else if (context instanceof ContextWrapper) {