Enable variable size thumbnail for large screen
- Introduced a feature flag
- Refresh TaskView size when thumbnail is refreshed or Recents resizes
- Disable edge scale down in large screens
- Added temp method to get task width/height ratio
- In fullscreen, scale down TaskThumbnailView and disable TaskView elevation
- Task boxing mechanism: http://screen/3NkePthAVUVH2Rv.png
Bug: 174464656
Test: Manually test overview and quickswitch for folded and unfolded, including with RTL.
Change-Id: I2ce24d588a246cc6a2408039a37d884021aa0800
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 7675a79..c2e5cda 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -32,6 +32,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
@@ -150,9 +151,11 @@
mTaskBeingDragged = view;
int upDirection = mRecentsView.getPagedOrientationHandler()
.getUpDirection(mIsRtl);
- if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
+ if (!SysUINavigationMode.getMode(mActivity).hasGestures || (
+ mActivity.getDeviceProfile().isTablet
+ && FeatureFlags.ENABLE_OVERVIEW_GRID.get())) {
// Don't allow swipe down to open if we don't support swipe up
- // to enter overview.
+ // to enter overview, or when grid layout is enabled.
directionsToDetectScroll = upDirection;
mAllowGoingUp = true;
mAllowGoingDown = false;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 9da306e..25c0928 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -49,6 +49,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
@@ -174,11 +175,13 @@
final RecentsView recentsView = v.getRecentsView();
int taskIndex = recentsView.indexOfChild(v);
- boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
- int startScroll = recentsView.getScrollOffset(taskIndex);
-
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
+ boolean parallaxCenterAndAdjacentTask =
+ taskIndex != recentsView.getCurrentPage() && !(dp.isTablet
+ && FeatureFlags.ENABLE_OVERVIEW_GRID.get());
+ int startScroll = recentsView.getScrollOffset(taskIndex);
+
TaskViewSimulator topMostSimulator = null;
if (tsv == null && targets.apps.length > 0) {
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 65bcf26..6f16781 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -276,8 +276,9 @@
int start = mOrientationState.getOrientationHandler()
.getPrimaryValue(mTaskRect.left, mTaskRect.top);
mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize;
- mScrollState.updateInterpolation(start);
- mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation);
+ mScrollState.updateInterpolation(mDp, start);
+ mCurveScale = TaskView.getCurveScaleForInterpolation(mDp,
+ mScrollState.linearInterpolation);
}
float progress = Utilities.boundToRange(fullScreenProgress.value, 0, 1);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d9d0a93..38d488c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -898,9 +898,14 @@
public void setFullscreenProgress(float fullscreenProgress) {
mFullscreenProgress = fullscreenProgress;
int taskCount = getTaskViewCount();
+ float accumulatedTranslationX = 0;
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
+ TaskView taskView = getTaskViewAt(i);
+ taskView.setFullscreenProgress(mFullscreenProgress);
+ taskView.setAccumulatedTranslationX(accumulatedTranslationX);
+ accumulatedTranslationX += taskView.getFullscreenTranslationX();
}
+
// Fade out the actions view quickly (0.1 range)
mActionsView.getFullscreenAlpha().setValue(
mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
@@ -934,6 +939,11 @@
setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
dp.widthPx - mInsets.right - mTempRect.right,
dp.heightPx - mInsets.bottom - mTempRect.bottom);
+ // Force TaskView to update size from thumbnail
+ final int taskCount = getTaskViewCount();
+ for (int i = 0; i < taskCount; i++) {
+ getTaskViewAt(i).updateTaskSize();
+ }
}
public void getTaskSize(Rect outRect) {
@@ -942,6 +952,11 @@
mLastComputedTaskSize.set(outRect);
}
+ /** Gets the last computed task size */
+ public Rect getLastComputedTaskSize() {
+ return mLastComputedTaskSize;
+ }
+
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
@@ -987,7 +1002,7 @@
final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i);
- mScrollState.updateInterpolation(
+ mScrollState.updateInterpolation(mActivity.getDeviceProfile(),
mOrientationHandler.getChildStartWithTranslation(page));
((PageCallbacks) page).onPageScroll(mScrollState);
}
@@ -1422,13 +1437,13 @@
/**
* Updates linearInterpolation for the provided child position
*/
- public void updateInterpolation(float childStart) {
+ public void updateInterpolation(DeviceProfile deviceProfile, float childStart) {
float pageCenter = childStart + halfPageSize;
float distanceFromScreenCenter = screenCenter - pageCenter;
// How far the page has to move from the center to be offscreen, taking into account
// the EDGE_SCALE_DOWN_FACTOR that will be applied at that position.
float distanceToReachEdge = halfScreenSize
- + halfPageSize * (1 - TaskView.EDGE_SCALE_DOWN_FACTOR);
+ + halfPageSize * (1 - TaskView.getEdgeScaleDownFactor(deviceProfile));
linearInterpolation = Math.min(1,
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
}
@@ -1444,12 +1459,13 @@
}
}
- private void addDismissedTaskAnimations(View taskView, long duration, PendingAnimation anim) {
+ private void addDismissedTaskAnimations(TaskView taskView, long duration,
+ PendingAnimation anim) {
// Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
// alpha is set to 0 so that it can be recycled in the view pool properly
anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
- FloatProperty<View> secondaryViewTranslate =
- mOrientationHandler.getSecondaryViewTranslate();
+ FloatProperty<TaskView> secondaryViewTranslate =
+ taskView.getDismissTaskTranslationProperty();
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
@@ -1515,7 +1531,7 @@
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
FloatProperty translationProperty = child instanceof TaskView
- ? ((TaskView) child).getPrimaryFillDismissGapTranslationProperty()
+ ? ((TaskView) child).getFillDismissGapTranslationProperty()
: mOrientationHandler.getPrimaryViewTranslate();
ResourceProvider rp = DynamicResource.provider(mActivity);
@@ -1971,7 +1987,8 @@
// Find the task's scale based on its offscreen progress, then see how far it still needs to
// move to be completely offscreen.
Utilities.scaleRectFAboutCenter(taskPosition,
- TaskView.getCurveScaleForInterpolation(centerToOffscreenProgress));
+ TaskView.getCurveScaleForInterpolation(mActivity.getDeviceProfile(),
+ centerToOffscreenProgress));
distanceToOffscreen = desiredLeft - taskPosition.left;
// Finally, we need to account for RecentsView scale, because it moves tasks based on its
// pivot. To do this, we move the task position to where it would be offscreen at scale = 1
@@ -1990,7 +2007,7 @@
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView task = getTaskViewAt(i);
- mOrientationHandler.getSecondaryViewTranslate().set(task, translation / getScaleY());
+ task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY());
}
mLiveTileTaskViewSimulator.recentsViewSecondaryTranslation.value = translation;
}
@@ -2359,6 +2376,52 @@
}
@Override
+ protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
+ ComputePageScrollsLogic scrollLogic) {
+ boolean pageScrollChanged = super.getPageScrolls(outPageScrolls, layoutChildren,
+ scrollLogic);
+
+ final int taskCount = getTaskViewCount();
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (childCount < mTaskViewStartIndex) {
+ continue;
+ }
+
+ final TaskView taskView = getTaskViewAt(
+ Utilities.boundToRange(i, mTaskViewStartIndex, taskCount - 1));
+ float scrollDiff =
+ taskView.getFullscreenTranslationX() + taskView.getAccumulatedTranslationX();
+ if (scrollDiff != 0) {
+ outPageScrolls[i] += scrollDiff;
+ pageScrollChanged = true;
+ }
+ }
+ return pageScrollChanged;
+ }
+
+ @Override
+ protected int getChildOffset(int index) {
+ if (index < mTaskViewStartIndex) {
+ return super.getChildOffset(index);
+ }
+
+ final TaskView taskView = getTaskViewAt(
+ Utilities.boundToRange(index, mTaskViewStartIndex, getTaskViewCount() - 1));
+ return super.getChildOffset(index) + (int) taskView.getFullscreenTranslationX()
+ + (int) taskView.getAccumulatedTranslationX();
+ }
+
+ @Override
+ protected int getChildVisibleSize(int index) {
+ final TaskView taskView = getTaskViewAtByAbsoluteIndex(index);
+ if (taskView == null) {
+ return super.getChildVisibleSize(index);
+ }
+ return super.getChildVisibleSize(index) - (int) taskView.getFullscreenTranslationX();
+ }
+
+ @Override
protected int computeMaxScroll() {
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 445e490..3bd883d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -51,6 +51,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
@@ -110,6 +111,9 @@
private boolean mOverlayEnabled;
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
+ // TODO(b/179466077): Remove when proper API is ready.
+ private Float mThumbnailRatio = null;
+
public TaskThumbnailView(Context context) {
this(context, null);
}
@@ -450,6 +454,31 @@
return mThumbnailData.isRealSnapshot;
}
+ // TODO(b/179466077): Remove when proper API is ready.
+ public float getThumbnailRatio() {
+ // API is ready.
+ if (mThumbnailRatio != null) {
+ return mThumbnailRatio;
+ }
+
+ if (mThumbnailData == null || mThumbnailData.thumbnail == null) {
+ final float[] thumbnailRatios =
+ new float[]{0.8882452f, 1.2834098f, 0.5558415f, 2.15625f};
+ // Use key's hash code to return a deterministic thumbnail ratio.
+ mThumbnailRatio = thumbnailRatios[mTask.key.hashCode() % thumbnailRatios.length];
+ return mThumbnailRatio;
+ }
+
+ float surfaceWidth = mThumbnailData.thumbnail.getWidth() / mThumbnailData.scale;
+ float surfaceHeight = mThumbnailData.thumbnail.getHeight() / mThumbnailData.scale;
+ float availableWidth = surfaceWidth
+ - (mThumbnailData.insets.left + mThumbnailData.insets.right);
+ float availableHeight = surfaceHeight
+ - (mThumbnailData.insets.top + mThumbnailData.insets.bottom);
+ mThumbnailRatio = availableWidth / availableHeight;
+ return mThumbnailRatio;
+ }
+
/**
* Utility class to position the thumbnail in the TaskView
*/
@@ -480,9 +509,11 @@
float scale = thumbnailData.scale;
final float thumbnailScale;
- // Landscape vs portrait change
+ // Landscape vs portrait change.
+ // Note: Disable rotation in grid layout.
boolean windowingModeSupportsRotation = !dp.isMultiWindowMode
- && thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
+ && thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN
+ && !(dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get());
isOrientationDifferent = isOrientationChange(deltaRotate)
&& windowingModeSupportsRotation;
if (canvasWidth == 0 || canvasHeight == 0 || scale == 0) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 59cf3b2..6709c2e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -30,6 +30,8 @@
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.comp;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
@@ -61,6 +63,7 @@
import android.view.Surface;
import android.view.TouchDelegate;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
@@ -72,6 +75,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -120,10 +124,8 @@
*/
public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
- /**
- * How much to scale down pages near the edge of the screen.
- */
- public static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
+ private static final float EDGE_SCALE_DOWN_FACTOR_CAROUSEL = 0.03f;
+ private static final float EDGE_SCALE_DOWN_FACTOR_GRID = 0.00f;
public static final long SCALE_ICON_DURATION = 120;
private static final long DIM_ANIM_DURATION = 700;
@@ -152,29 +154,29 @@
}
};
- private static final FloatProperty<TaskView> FILL_DISMISS_GAP_TRANSLATION_X =
- new FloatProperty<TaskView>("fillDismissGapTranslationX") {
+ private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
+ new FloatProperty<TaskView>("dismissTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
- taskView.setFillDismissGapTranslationX(v);
+ taskView.setDismissTranslationX(v);
}
@Override
public Float get(TaskView taskView) {
- return taskView.mFillDismissGapTranslationX;
+ return taskView.mDismissTranslationX;
}
};
- private static final FloatProperty<TaskView> FILL_DISMISS_GAP_TRANSLATION_Y =
- new FloatProperty<TaskView>("fillDismissGapTranslationY") {
+ private static final FloatProperty<TaskView> DISMISS_TRANSLATION_Y =
+ new FloatProperty<TaskView>("dismissTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
- taskView.setFillDismissGapTranslationY(v);
+ taskView.setDismissTranslationY(v);
}
@Override
public Float get(TaskView taskView) {
- return taskView.mFillDismissGapTranslationY;
+ return taskView.mDismissTranslationY;
}
};
@@ -204,6 +206,32 @@
}
};
+ private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_X =
+ new FloatProperty<TaskView>("taskResistanceTranslationX") {
+ @Override
+ public void setValue(TaskView taskView, float v) {
+ taskView.setTaskResistanceTranslationX(v);
+ }
+
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.mTaskResistanceTranslationX;
+ }
+ };
+
+ private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_Y =
+ new FloatProperty<TaskView>("taskResistanceTranslationY") {
+ @Override
+ public void setValue(TaskView taskView, float v) {
+ taskView.setTaskResistanceTranslationY(v);
+ }
+
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.mTaskResistanceTranslationY;
+ }
+ };
+
private final OnAttachStateChangeListener mTaskMenuStateListener =
new OnAttachStateChangeListener() {
@Override
@@ -228,15 +256,22 @@
private final DigitalWellBeingToast mDigitalWellBeingToast;
private float mCurveScale;
private float mFullscreenProgress;
+ private float mScaleAtFullscreen = 1;
+ private float mFullscreenScale = 1;
private final FullscreenDrawParams mCurrentFullscreenParams;
private final StatefulActivity mActivity;
// Various causes of changing primary translation, which we aggregate to setTranslationX/Y().
- // TODO: We should do this for secondary translation properties as well.
- private float mFillDismissGapTranslationX;
- private float mFillDismissGapTranslationY;
+ private float mDismissTranslationX;
+ private float mDismissTranslationY;
private float mTaskOffsetTranslationX;
private float mTaskOffsetTranslationY;
+ private float mTaskResistanceTranslationX;
+ private float mTaskResistanceTranslationY;
+ // The following translation variables should only be used in the same orientation as Launcher.
+ private float mFullscreenTranslationX;
+ private float mAccumulatedTranslationX;
+ private float mBoxTranslationY;
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
@@ -425,6 +460,7 @@
cancelPendingLoadTasks();
mTask = task;
mSnapshotView.bind(task);
+ updateTaskSize();
setOrientationState(orientedState);
}
@@ -668,10 +704,12 @@
protected void resetViewTransforms() {
setCurveScale(1);
- mFillDismissGapTranslationX = mTaskOffsetTranslationX = 0f;
- mFillDismissGapTranslationY = mTaskOffsetTranslationY = 0f;
- setTranslationX(0f);
- setTranslationY(0f);
+ // fullscreenTranslation and accumulatedTranslation should not be reset, as
+ // resetViewTransforms is called during Quickswitch scrolling.
+ mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = 0f;
+ mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f;
+ applyTranslationX();
+ applyTranslationY();
setTranslationZ(0);
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
@@ -684,6 +722,7 @@
@Override
public void onRecycle() {
+ mFullscreenTranslationX = mAccumulatedTranslationX = mBoxTranslationY = 0f;
resetViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
@@ -702,7 +741,7 @@
float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
float curveScaleForCurveInterpolation = getCurveScaleForCurveInterpolation(
- curveInterpolation);
+ mActivity.getDeviceProfile(), curveInterpolation);
mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
setCurveScale(curveScaleForCurveInterpolation);
@@ -787,40 +826,70 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- setPivotX((right - left) * 0.5f);
- setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+ if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? (right - left) : 0);
+ setPivotY(0);
+ } else {
+ setPivotX((right - left) * 0.5f);
+ setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+ }
if (Utilities.ATLEAST_Q) {
SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
}
}
- public static float getCurveScaleForInterpolation(float linearInterpolation) {
+ /**
+ * How much to scale down pages near the edge of the screen according to linearInterpolation.
+ */
+ public static float getCurveScaleForInterpolation(DeviceProfile deviceProfile,
+ float linearInterpolation) {
float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
- return getCurveScaleForCurveInterpolation(curveInterpolation);
+ return getCurveScaleForCurveInterpolation(deviceProfile, curveInterpolation);
}
- private static float getCurveScaleForCurveInterpolation(float curveInterpolation) {
- return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
+ private static float getCurveScaleForCurveInterpolation(DeviceProfile deviceProfile,
+ float curveInterpolation) {
+ return 1 - curveInterpolation * getEdgeScaleDownFactor(deviceProfile);
+ }
+
+ /**
+ * How much to scale down pages near the edge of the screen.
+ */
+ public static float getEdgeScaleDownFactor(DeviceProfile deviceProfile) {
+ if (deviceProfile.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ return EDGE_SCALE_DOWN_FACTOR_GRID;
+ } else {
+ return EDGE_SCALE_DOWN_FACTOR_CAROUSEL;
+ }
}
private void setCurveScale(float curveScale) {
mCurveScale = curveScale;
- setScaleX(mCurveScale);
- setScaleY(mCurveScale);
+ applyScale();
+ }
+
+ private void setFullscreenScale(float fullscreenScale) {
+ mFullscreenScale = fullscreenScale;
+ applyScale();
+ }
+
+ private void applyScale() {
+ setScaleX(mCurveScale * mFullscreenScale);
+ setScaleY(mCurveScale * mFullscreenScale);
}
public float getCurveScale() {
return mCurveScale;
}
- private void setFillDismissGapTranslationX(float x) {
- mFillDismissGapTranslationX = x;
+ private void setDismissTranslationX(float x) {
+ mDismissTranslationX = x;
applyTranslationX();
}
- private void setFillDismissGapTranslationY(float y) {
- mFillDismissGapTranslationY = y;
+ private void setDismissTranslationY(float y) {
+ mDismissTranslationY = y;
applyTranslationY();
}
@@ -834,17 +903,59 @@
applyTranslationY();
}
+ private void setTaskResistanceTranslationX(float x) {
+ mTaskResistanceTranslationX = x;
+ applyTranslationX();
+ }
+
+ private void setTaskResistanceTranslationY(float y) {
+ mTaskResistanceTranslationY = y;
+ applyTranslationY();
+ }
+
+ private void setFullscreenTranslationX(float fullscreenTranslationX) {
+ mFullscreenTranslationX = fullscreenTranslationX;
+ applyTranslationX();
+ }
+
+ public float getFullscreenTranslationX() {
+ return mFullscreenTranslationX;
+ }
+
+ public void setAccumulatedTranslationX(float accumulatedTranslationX) {
+ mAccumulatedTranslationX = accumulatedTranslationX;
+ applyTranslationX();
+ }
+
+ public float getAccumulatedTranslationX() {
+ return mAccumulatedTranslationX;
+ }
+
+ private void setBoxTranslationY(float boxTranslationY) {
+ mBoxTranslationY = boxTranslationY;
+ applyTranslationY();
+ }
+
private void applyTranslationX() {
- setTranslationX(mFillDismissGapTranslationX + mTaskOffsetTranslationX);
+ setTranslationX(
+ mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
+ + mFullscreenTranslationX + mAccumulatedTranslationX);
}
private void applyTranslationY() {
- setTranslationY(mFillDismissGapTranslationY + mTaskOffsetTranslationY);
+ setTranslationY(
+ mDismissTranslationY + mTaskOffsetTranslationY + mTaskResistanceTranslationY
+ + mBoxTranslationY);
}
- public FloatProperty<TaskView> getPrimaryFillDismissGapTranslationProperty() {
+ public FloatProperty<TaskView> getFillDismissGapTranslationProperty() {
return getPagedOrientationHandler().getPrimaryValue(
- FILL_DISMISS_GAP_TRANSLATION_X, FILL_DISMISS_GAP_TRANSLATION_Y);
+ DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y);
+ }
+
+ public FloatProperty<TaskView> getDismissTaskTranslationProperty() {
+ return getPagedOrientationHandler().getSecondaryValue(
+ DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y);
}
public FloatProperty<TaskView> getPrimaryTaskOffsetTranslationProperty() {
@@ -852,6 +963,11 @@
TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
}
+ public FloatProperty<TaskView> getTaskResistanceTranslationProperty() {
+ return getPagedOrientationHandler().getSecondaryValue(
+ TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
+ }
+
@Override
public boolean hasOverlappingRendering() {
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
@@ -987,6 +1103,8 @@
setClipChildren(!isFullscreen);
setClipToPadding(!isFullscreen);
+ updateTaskScaling();
+
TaskThumbnailView thumbnail = getThumbnail();
updateCurrentFullscreenParams(thumbnail.getPreviewPositionHelper());
@@ -1012,6 +1130,83 @@
previewPositionHelper);
}
+ void updateTaskSize() {
+ ViewGroup.LayoutParams params = getLayoutParams();
+ if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ final int thumbnailPadding = (int) getResources().getDimension(
+ R.dimen.task_thumbnail_top_margin);
+
+ Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
+ int taskWidth = lastComputedTaskSize.width();
+ int taskHeight = lastComputedTaskSize.height();
+ int boxLength = Math.max(taskWidth, taskHeight);
+ float thumbnailRatio = mSnapshotView.getThumbnailRatio();
+
+ int expectedWidth;
+ int expectedHeight;
+ if (thumbnailRatio > 1) {
+ expectedWidth = boxLength;
+ expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
+ } else {
+ expectedWidth = (int) (boxLength * thumbnailRatio);
+ expectedHeight = boxLength + thumbnailPadding;
+ }
+
+ float heightDiff = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
+ setBoxTranslationY(heightDiff);
+
+ if (expectedWidth > taskWidth) {
+ // In full screen, expectedWidth should not be larger than taskWidth.
+ mScaleAtFullscreen = taskWidth / (float) expectedWidth;
+ } else if (expectedHeight - thumbnailPadding > taskHeight) {
+ // In full screen, expectedHeight should not be larger than taskHeight.
+ mScaleAtFullscreen = taskHeight / (float) (expectedHeight - thumbnailPadding);
+ } else {
+ mScaleAtFullscreen = 1f;
+ }
+
+ if (params.width != expectedWidth || params.height != expectedHeight) {
+ params.width = expectedWidth;
+ params.height = expectedHeight;
+ setLayoutParams(params);
+ }
+ } else {
+ setBoxTranslationY(0);
+ if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
+ params.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ params.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ setLayoutParams(params);
+ }
+ }
+ updateTaskScaling();
+ }
+
+ private void updateTaskScaling() {
+ if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ ViewGroup.LayoutParams params = getLayoutParams();
+ if (params.width == ViewGroup.LayoutParams.MATCH_PARENT
+ || params.height == ViewGroup.LayoutParams.MATCH_PARENT) {
+ // Snapshot is not loaded yet, skip.
+ return;
+ }
+
+ float progress = EXAGGERATED_EASE.getInterpolation(mFullscreenProgress);
+ setFullscreenScale(Utilities.mapRange(progress, 1f, mScaleAtFullscreen));
+
+ float widthDiff = params.width * (1 - mFullscreenScale);
+ setFullscreenTranslationX(getFullscreenTrans(
+ getLayoutDirection() == LAYOUT_DIRECTION_RTL ? -widthDiff : widthDiff));
+ } else {
+ setFullscreenScale(1);
+ setFullscreenTranslationX(0);
+ }
+ }
+
+ private float getFullscreenTrans(float endTranslation) {
+ float progress = ACCEL_DEACCEL.getInterpolation(mFullscreenProgress);
+ return Utilities.mapRange(progress, 0, endTranslation);
+ }
+
public boolean isRunningTask() {
if (getRecentsView() == null) {
return false;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 4303dee..ada297f 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -745,6 +745,11 @@
return mOrientationHandler.getChildStart(pageAtIndex);
}
+ protected int getChildVisibleSize(int index) {
+ View layout = getPageAt(index);
+ return mOrientationHandler.getMeasuredSize(layout);
+ }
+
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
int page = indexToPage(indexOfChild(child));
@@ -1457,8 +1462,7 @@
}
private int getDisplacementFromScreenCenter(int childIndex, int screenCenter) {
- View layout = getPageAt(childIndex);
- int childSize = mOrientationHandler.getMeasuredSize(layout);
+ int childSize = getChildVisibleSize(childIndex);
int halfChildSize = (childSize / 2);
int childCenter = getChildOffset(childIndex) + halfChildSize;
return childCenter - screenCenter;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index ac0083c..2b373a8 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -214,6 +214,10 @@
public static final BooleanFlag ENABLE_TASKBAR = new DeviceFlag(
"ENABLE_TASKBAR", false, "Allows a system Taskbar to be shown on larger devices.");
+ public static final BooleanFlag ENABLE_OVERVIEW_GRID = new DeviceFlag(
+ "ENABLE_OVERVIEW_GRID", false, "Uses grid overview layout. "
+ + "Only applicable on large screen devices.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {