Merge "Animate grid tasks to modal state." into tm-qpr-dev

This commit is contained in:
Pat Manning
2023-02-22 11:18:47 +00:00
committed by Android (Google) Code Review
9 changed files with 174 additions and 35 deletions

View File

@@ -18,12 +18,12 @@ package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.views.RecentsView;
/**
@@ -70,13 +70,22 @@ public class OverviewModalTaskState extends OverviewState {
}
}
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
Point taskSize = activity.<RecentsView>getOverviewPanel().getSelectedTaskSize();
Rect modalTaskSize = new Rect();
activity.<RecentsView>getOverviewPanel().getModalTaskSize(modalTaskSize);
@Override
public boolean isTaskbarStashed(Launcher launcher) {
if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
return true;
}
return super.isTaskbarStashed(launcher);
}
float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
(float) modalTaskSize.width() / taskSize.x);
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
RecentsView recentsView = activity.<RecentsView>getOverviewPanel();
Rect taskSize = recentsView.getSelectedTaskBounds();
Rect modalTaskSize = new Rect();
recentsView.getModalTaskSize(modalTaskSize);
float scale = Math.min((float) modalTaskSize.height() / taskSize.height(),
(float) modalTaskSize.width() / taskSize.width());
return new float[] {scale, NO_OFFSET};
}

View File

@@ -52,6 +52,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
@@ -339,12 +340,21 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
*/
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
calculateTaskSize(context, dp, outRect);
float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
boolean isGridOnlyOverview = dp.isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get();
int claimedSpaceBelow = isGridOnlyOverview
? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarSize
: (dp.heightPx - outRect.bottom - dp.getInsets().bottom);
int minimumHorizontalPadding = 0;
if (!isGridOnlyOverview) {
float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
minimumHorizontalPadding =
Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2);
}
calculateTaskSizeInternal(
context, dp,
dp.overviewTaskMarginPx,
dp.heightPx - outRect.bottom - dp.getInsets().bottom,
Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2),
claimedSpaceBelow,
minimumHorizontalPadding,
1f /*maxScale*/,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
outRect);

View File

@@ -80,9 +80,9 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
boolean isTablet = activity.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get();
// Add overview actions to the menu when in in-place rotate landscape mode.
if ((!canLauncherRotate && isInLandscape)
|| (isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get())) {
if ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview) {
// Add screenshot action to task menu.
List<SystemShortcut> screenshotShortcuts = TaskShortcutFactory.SCREENSHOT
.getShortcuts(activity, taskContainer);

View File

@@ -15,6 +15,8 @@
*/
package com.android.quickstep.fallback;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
@@ -200,8 +202,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
}
@Override
public void setModalStateEnabled(boolean isModalState, boolean animate) {
if (isModalState) {
public void setModalStateEnabled(int taskId, boolean animate) {
if (taskId != INVALID_TASK_ID) {
setSelectedTask(taskId);
mActivity.getStateManager().goToState(RecentsState.MODAL_TASK, animate);
} else {
if (mActivity.isInState(RecentsState.MODAL_TASK)) {

View File

@@ -15,6 +15,8 @@
*/
package com.android.quickstep.views;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -171,8 +173,9 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
}
@Override
public void setModalStateEnabled(boolean isModalState, boolean animate) {
if (isModalState) {
public void setModalStateEnabled(int taskId, boolean animate) {
if (taskId != INVALID_TASK_ID) {
setSelectedTask(taskId);
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate);
} else {
if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {

View File

@@ -303,6 +303,10 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
return mDp.getOverviewActionsClaimedSpaceBelow();
}
if (mDp.isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
return mDp.stashedTaskbarSize;
}
// Align to bottom of task Rect.
return mDp.heightPx - mTaskSize.bottom - mDp.overviewActionsTopMarginPx
- mDp.overviewActionsHeight;

View File

@@ -453,6 +453,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
private TaskView mSelectedTask = null;
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
@Nullable
protected Float mLastComputedTaskStartPushOutDistance = null;
@@ -1084,6 +1085,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
super.draw(canvas);
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
if (isModal()) {
// Do not scroll when clicking on a modal grid task, as it will already be centered
// on screen.
return false;
}
return super.requestChildRectangleOnScreen(child, rectangle, immediate);
}
public void addSideTaskLaunchCallback(RunnableList callback) {
if (mSideTaskLaunchCallback == null) {
mSideTaskLaunchCallback = new RunnableList();
@@ -1272,7 +1283,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
*/
@Nullable
public TaskView getTaskViewByTaskId(int taskId) {
if (taskId == -1) {
if (taskId == INVALID_TASK_ID) {
return null;
}
@@ -1920,7 +1931,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private void onOrientationChanged() {
// If overview is in modal state when rotate, reset it to overview state without running
// animation.
setModalStateEnabled(/* isModalState= */ false, /* animate= */ false);
setModalStateEnabled(/* taskId= */ INVALID_TASK_ID, /* animate= */ false);
if (isSplitSelectionActive()) {
onRotateInSplitSelectionState();
}
@@ -1993,12 +2004,33 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
/**
* Returns the size of task selected to enter modal state.
* Sets the last TaskView selected.
*/
public Point getSelectedTaskSize() {
mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(),
mTempRect);
return new Point(mTempRect.width(), mTempRect.height());
public void setSelectedTask(int lastSelectedTaskId) {
mSelectedTask = getTaskViewByTaskId(lastSelectedTaskId);
}
/**
* Returns the bounds of the task selected to enter modal state.
*/
public Rect getSelectedTaskBounds() {
if (mSelectedTask == null) {
return mLastComputedTaskSize;
}
return getTaskBounds(mSelectedTask);
}
private Rect getTaskBounds(TaskView taskView) {
int selectedPage = indexOfChild(taskView);
int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
int selectedPageScroll = getScrollForPage(selectedPage);
boolean isTopRow = taskView != null && mTopRowIdSet.contains(taskView.getTaskViewId());
Rect outRect = new Rect(mLastComputedTaskSize);
outRect.offset(
-(primaryScroll - (selectedPageScroll + getOffsetFromScrollPosition(selectedPage))),
(int) (showAsGrid() && ENABLE_GRID_ONLY_OVERVIEW.get() && !isTopRow
? mTopBottomRowHeightDiff : 0));
return outRect;
}
/** Gets the last computed task size */
@@ -4122,8 +4154,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private void updatePivots() {
if (mOverviewSelectEnabled) {
setPivotX(mLastComputedTaskSize.centerX());
setPivotY(mLastComputedTaskSize.bottom);
getModalTaskSize(mTempRect);
Rect selectedTaskPosition = getSelectedTaskBounds();
Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition,
mTempPointF);
setPivotX(mTempPointF.x);
setPivotY(mTempPointF.y);
} else {
getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
mActivity.getDeviceProfile(), mTempPointF);
@@ -4136,11 +4173,17 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
float offset = mAdjacentPageHorizontalOffset;
float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness);
int count = getChildCount();
boolean showAsGrid = showAsGrid();
TaskView runningTask = mRunningTaskViewId == -1 || !mRunningTaskTileHidden
? null : getRunningTaskView();
int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
int modalMidpoint = getCurrentPage();
boolean isModalGridWithoutFocusedTask =
showAsGrid && ENABLE_GRID_ONLY_OVERVIEW.get() && mTaskModalness > 0;
if (isModalGridWithoutFocusedTask) {
modalMidpoint = indexOfChild(mSelectedTask);
}
float midpointOffsetSize = 0;
float leftOffsetSize = midpoint - 1 >= 0
@@ -4150,7 +4193,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
? getHorizontalOffsetSize(midpoint + 1, midpoint, offset)
: 0;
boolean showAsGrid = showAsGrid();
float modalMidpointOffsetSize = 0;
float modalLeftOffsetSize = 0;
float modalRightOffsetSize = 0;
@@ -4178,23 +4220,34 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
: i < midpoint
? leftOffsetSize
: rightOffsetSize;
if (isModalGridWithoutFocusedTask) {
gridOffsetSize = getHorizontalOffsetSize(i, modalMidpoint, modalOffset);
gridOffsetSize = Math.abs(gridOffsetSize) * (i <= modalMidpoint ? 1 : -1);
}
float modalTranslation = i == modalMidpoint
? modalMidpointOffsetSize
: showAsGrid
? gridOffsetSize
: i < modalMidpoint ? modalLeftOffsetSize : modalRightOffsetSize;
float totalTranslation = translation + modalTranslation;
float totalTranslationX = translation + modalTranslation;
View child = getChildAt(i);
FloatProperty translationProperty = child instanceof TaskView
FloatProperty translationPropertyX = child instanceof TaskView
? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
: mOrientationHandler.getPrimaryViewTranslate();
translationProperty.set(child, totalTranslation);
translationPropertyX.set(child, totalTranslationX);
if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
runActionOnRemoteHandles(
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
.taskPrimaryTranslation.value = totalTranslation);
.taskPrimaryTranslation.value = totalTranslationX);
redrawLiveTile();
}
if (showAsGrid && ENABLE_GRID_ONLY_OVERVIEW.get() && child instanceof TaskView) {
float totalTranslationY = getVerticalOffsetSize(i, modalOffset);
FloatProperty translationPropertyY =
((TaskView) child).getSecondaryTaskOffsetTranslationProperty();
translationPropertyY.set(child, totalTranslationY);
}
}
updateCurveProperties();
}
@@ -4292,6 +4345,38 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return distanceToOffscreen * offsetProgress;
}
/**
* Computes the vertical distance to offset a given child such that it is completely offscreen.
*
* @param offsetProgress From 0 to 1 where 0 means no offset and 1 means offset offscreen.
*/
private float getVerticalOffsetSize(int childIndex, float offsetProgress) {
if (offsetProgress == 0 || !(showAsGrid() && ENABLE_GRID_ONLY_OVERVIEW.get())
|| mSelectedTask == null) {
// Don't bother calculating everything below if we won't offset vertically.
return 0;
}
// First, get the position of the task relative to the top row.
TaskView child = getTaskViewAt(childIndex);
Rect taskPosition = getTaskBounds(child);
boolean isSelectedTaskTopRow = mTopRowIdSet.contains(mSelectedTask.getTaskViewId());
boolean isChildTopRow = mTopRowIdSet.contains(child.getTaskViewId());
// Whether the task should be shifted to the top.
boolean isTopShift = !isSelectedTaskTopRow && isChildTopRow;
boolean isBottomShift = isSelectedTaskTopRow && !isChildTopRow;
// Next, calculate the distance to move the task off screen at scale = 1.
float distanceToOffscreen = 0;
if (isTopShift) {
distanceToOffscreen = -taskPosition.bottom;
} else if (isBottomShift) {
distanceToOffscreen = mActivity.getDeviceProfile().heightPx - taskPosition.top;
}
return distanceToOffscreen * offsetProgress;
}
protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
@@ -4391,9 +4476,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
* Resets the visuals when exit modal state.
*/
public void resetModalVisuals() {
TaskView taskView = getCurrentPageTaskView();
if (taskView != null) {
taskView.getThumbnail().getTaskOverlay().resetModalVisuals();
if (mSelectedTask != null) {
mSelectedTask.getThumbnail().getTaskOverlay().resetModalVisuals();
}
}
@@ -5395,6 +5479,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
if (mOverviewSelectEnabled != overviewSelectEnabled) {
mOverviewSelectEnabled = overviewSelectEnabled;
updatePivots();
if (!mOverviewSelectEnabled) {
setSelectedTask(INVALID_TASK_ID);
}
}
}
@@ -5465,7 +5552,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private void setTaskModalness(float modalness) {
mTaskModalness = modalness;
updatePageOffsets();
if (getCurrentPageTaskView() != null) {
if (mSelectedTask != null) {
mSelectedTask.setModalness(modalness);
} else if (getCurrentPageTaskView() != null) {
getCurrentPageTaskView().setModalness(modalness);
}
// Only show actions view when it's modal for in-place landscape mode.
@@ -5480,7 +5569,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
/** Enables or disables modal state for RecentsView */
public abstract void setModalStateEnabled(boolean isModalState, boolean animate);
public abstract void setModalStateEnabled(int taskId, boolean animate);
public TaskOverlayFactory getTaskOverlayFactory() {
return mTaskOverlayFactory;

View File

@@ -1445,6 +1445,11 @@ public class TaskView extends FrameLayout implements Reusable {
TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
}
public FloatProperty<TaskView> getSecondaryTaskOffsetTranslationProperty() {
return getPagedOrientationHandler().getSecondaryValue(
TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
}
public FloatProperty<TaskView> getTaskResistanceTranslationProperty() {
return getPagedOrientationHandler().getSecondaryValue(
TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);

View File

@@ -38,6 +38,7 @@ import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
@@ -342,6 +343,21 @@ public final class Utilities {
return scale;
}
/**
* Sets the x and y pivots for scaling from one Rect to another.
*
* @param src the source rectangle to scale from.
* @param dst the destination rectangle to scale to.
* @param outPivot the pivots set for scaling from src to dst.
*/
public static void getPivotsForScalingRectToRect(Rect src, Rect dst, PointF outPivot) {
float pivotXPct = ((float) src.left - dst.left) / ((float) dst.width() - src.width());
outPivot.x = dst.left + dst.width() * pivotXPct;
float pivotYPct = ((float) src.top - dst.top) / ((float) dst.height() - src.height());
outPivot.y = dst.top + dst.height() * pivotYPct;
}
/**
* Maps t from one range to another range.
* @param t The value to map.