Snap for 7397158 from 1919443e37 to sc-v2-release
Change-Id: I67673b4f906bf11206673e9cc024af51817f5a40
This commit is contained in:
+5
-4
@@ -48,6 +48,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shadows.ShadowDeviceFlag;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LauncherModelHelper;
|
||||
import com.android.launcher3.util.ViewOnDrawExecutor;
|
||||
@@ -239,8 +240,8 @@ public final class WidgetsPredicationUpdateTaskTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageToBindSynchronously() {
|
||||
return 0;
|
||||
public IntSet getPagesToBindSynchronously() {
|
||||
return IntSet.wrap(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,7 +260,7 @@ public final class WidgetsPredicationUpdateTaskTest {
|
||||
public void finishFirstPageBind(ViewOnDrawExecutor executor) { }
|
||||
|
||||
@Override
|
||||
public void finishBindingItems(int pageBoundFirst) { }
|
||||
public void finishBindingItems(IntSet pagesBoundFirst) { }
|
||||
|
||||
@Override
|
||||
public void preAddApps() { }
|
||||
@@ -287,7 +288,7 @@ public final class WidgetsPredicationUpdateTaskTest {
|
||||
public void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
|
||||
|
||||
@Override
|
||||
public void onPageBoundSynchronously(int page) { }
|
||||
public void onPagesBoundSynchronously(IntSet pages) { }
|
||||
|
||||
@Override
|
||||
public void executeOnNextDraw(ViewOnDrawExecutor executor) { }
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.android.launcher3.taskbar.TaskbarManager;
|
||||
import com.android.launcher3.taskbar.TaskbarStateHandler;
|
||||
import com.android.launcher3.uioverrides.RecentsViewStateController;
|
||||
import com.android.launcher3.util.ActivityOptionsWrapper;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ObjectWrapper;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
@@ -410,8 +411,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishBindingItems(int pageBoundFirst) {
|
||||
super.finishBindingItems(pageBoundFirst);
|
||||
public void finishBindingItems(IntSet pagesBoundFirst) {
|
||||
super.finishBindingItems(pagesBoundFirst);
|
||||
// Instantiate and initialize WellbeingModel now that its loading won't interfere with
|
||||
// populating workspace.
|
||||
// TODO: Find a better place for this
|
||||
|
||||
@@ -691,7 +691,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
floatingIconBounds.right += offsetX;
|
||||
floatingIconBounds.bottom += offsetY;
|
||||
|
||||
SurfaceParams[] params = new SurfaceParams[appTargets.length];
|
||||
ArrayList<SurfaceParams> params = new ArrayList<>();
|
||||
for (int i = appTargets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = appTargets[i];
|
||||
SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
|
||||
@@ -743,9 +743,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
.withWindowCrop(crop)
|
||||
.withAlpha(1f);
|
||||
}
|
||||
params[i] = builder.build();
|
||||
params.add(builder.build());
|
||||
}
|
||||
surfaceApplier.scheduleApply(params);
|
||||
|
||||
if (navBarTarget != null) {
|
||||
final SurfaceParams.Builder navBuilder =
|
||||
@@ -759,8 +758,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
} else {
|
||||
navBuilder.withAlpha(mNavFadeOut.value);
|
||||
}
|
||||
surfaceApplier.scheduleApply(navBuilder.build());
|
||||
params.add(navBuilder.build());
|
||||
}
|
||||
|
||||
surfaceApplier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -791,6 +792,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(floatingView);
|
||||
openingTargets.addReleaseCheck(surfaceApplier);
|
||||
|
||||
RemoteAnimationTargetCompat navBarTarget = openingTargets.getNavBarRemoteAnimationTarget();
|
||||
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setDuration(APP_LAUNCH_DURATION);
|
||||
@@ -832,6 +835,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
|
||||
EXAGGERATED_EASE);
|
||||
|
||||
final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
|
||||
NAV_FADE_OUT_INTERPOLATOR);
|
||||
final FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
|
||||
ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
widgetBackgroundBounds.set(mDx.value - mWidth.value / 2f,
|
||||
@@ -847,7 +855,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
matrix.postScale(mAppWindowScale, mAppWindowScale, widgetBackgroundBounds.left,
|
||||
widgetBackgroundBounds.top);
|
||||
|
||||
SurfaceParams[] params = new SurfaceParams[appTargets.length];
|
||||
ArrayList<SurfaceParams> params = new ArrayList<>();
|
||||
float floatingViewAlpha = appTargetsAreTranslucent ? 1 - mPreviewAlpha.value : 1;
|
||||
for (int i = appTargets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = appTargets[i];
|
||||
@@ -861,9 +869,23 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
.withAlpha(mPreviewAlpha.value)
|
||||
.withCornerRadius(mWindowRadius.value / mAppWindowScale);
|
||||
}
|
||||
params[i] = builder.build();
|
||||
params.add(builder.build());
|
||||
}
|
||||
surfaceApplier.scheduleApply(params);
|
||||
|
||||
if (navBarTarget != null) {
|
||||
final SurfaceParams.Builder navBuilder =
|
||||
new SurfaceParams.Builder(navBarTarget.leash);
|
||||
if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
|
||||
navBuilder.withMatrix(matrix)
|
||||
.withWindowCrop(appWindowCrop)
|
||||
.withAlpha(mNavFadeIn.value);
|
||||
} else {
|
||||
navBuilder.withAlpha(mNavFadeOut.value);
|
||||
}
|
||||
params.add(navBuilder.build());
|
||||
}
|
||||
|
||||
surfaceApplier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -106,8 +106,7 @@ public final class RecentsViewStateController extends
|
||||
float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
|
||||
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha, LINEAR);
|
||||
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS)
|
||||
&& mRecentsView.shouldShowOverviewActionsForState(state) ? 1 : 0;
|
||||
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
|
||||
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
|
||||
MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator(
|
||||
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
|
||||
|
||||
@@ -77,9 +77,7 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
|
||||
float clearAllButtonAlpha = state.hasClearAllButton() ? 1 : 0;
|
||||
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha, LINEAR);
|
||||
float overviewButtonAlpha =
|
||||
state.hasOverviewActions() && mRecentsView.shouldShowOverviewActionsForState(state)
|
||||
? 1 : 0;
|
||||
float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
|
||||
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
|
||||
MultiValueAlpha.VALUE, overviewButtonAlpha, LINEAR);
|
||||
|
||||
|
||||
@@ -26,14 +26,12 @@ import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.quickstep.FallbackActivityInterface;
|
||||
import com.android.quickstep.GestureState;
|
||||
import com.android.quickstep.RecentsActivity;
|
||||
@@ -122,6 +120,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected TaskView getHomeTaskView() {
|
||||
return mHomeTaskInfo != null ? getTaskView(mHomeTaskInfo.taskId) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAddStubTaskView(RunningTaskInfo runningTaskInfo) {
|
||||
if (mHomeTaskInfo != null && runningTaskInfo != null &&
|
||||
|
||||
@@ -32,7 +32,6 @@ import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.Utilities.squaredTouchSlop;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_5;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
@@ -341,6 +340,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private static final int ADDITION_TASK_DURATION = 200;
|
||||
private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
|
||||
private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
|
||||
private static final float ANIMATION_DISMISS_PROGRESS_MIDPOINT = 0.5f;
|
||||
|
||||
protected final RecentsOrientedState mOrientationState;
|
||||
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
|
||||
@@ -348,6 +348,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
protected SurfaceTransactionApplier mSyncTransactionApplier;
|
||||
protected int mTaskWidth;
|
||||
protected int mTaskHeight;
|
||||
// Used to position the top of a task in the top row of the grid
|
||||
private float mTaskGridVerticalDiff;
|
||||
// The vertical space one grid task takes + space between top and bottom row.
|
||||
private float mTopBottomRowHeightDiff;
|
||||
// mTaskGridVerticalDiff and mTopBottomRowHeightDiff summed together provides the top
|
||||
// position for bottom row of grid tasks.
|
||||
|
||||
protected final TransformParams mLiveTileParams = new TransformParams();
|
||||
protected final TaskViewSimulator mLiveTileTaskViewSimulator;
|
||||
protected final Rect mLastComputedTaskSize = new Rect();
|
||||
@@ -811,7 +818,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// taskview for entering split screen, we only pretend to dismiss the task
|
||||
if (child instanceof TaskView && child != mSplitHiddenTaskView) {
|
||||
TaskView taskView = (TaskView) child;
|
||||
mHasVisibleTaskData.delete(taskView.getTask().key.id);
|
||||
mHasVisibleTaskData.delete(taskView.getTaskId());
|
||||
mTaskViewPool.recycle(taskView);
|
||||
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
|
||||
}
|
||||
@@ -918,7 +925,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
public TaskView getTaskView(int taskId) {
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (taskView.hasTaskId(taskId)) {
|
||||
if (taskView.getTaskId() == taskId) {
|
||||
return taskView;
|
||||
}
|
||||
}
|
||||
@@ -1110,6 +1117,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
||||
taskView.bind(task, mOrientationState);
|
||||
}
|
||||
if (mFocusedTaskId == -1 && getTaskViewCount() > 0) {
|
||||
mFocusedTaskId = getTaskViewAt(0).getTaskId();
|
||||
}
|
||||
updateTaskSize();
|
||||
|
||||
if (mNextPage == INVALID_PAGE) {
|
||||
@@ -1166,7 +1176,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
public void resetTaskVisuals() {
|
||||
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (mIgnoreResetTaskId != taskView.getTask().key.id) {
|
||||
if (mIgnoreResetTaskId != taskView.getTaskId()) {
|
||||
taskView.resetViewTransforms();
|
||||
taskView.setStableAlpha(mContentAlpha);
|
||||
taskView.setFullscreenProgress(mFullscreenProgress);
|
||||
@@ -1285,6 +1295,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
|
||||
mLastComputedGridTaskSize, mOrientationHandler);
|
||||
|
||||
mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
|
||||
mTopBottomRowHeightDiff =
|
||||
mLastComputedGridTaskSize.height() + dp.overviewTaskThumbnailTopMarginPx
|
||||
+ mRowSpacing;
|
||||
|
||||
// Force TaskView to update size from thumbnail
|
||||
updateTaskSize();
|
||||
|
||||
@@ -1315,6 +1330,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* Updates TaskView scaling and translation required to support variable width.
|
||||
*/
|
||||
private void updateTaskSize() {
|
||||
updateTaskSize(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates TaskView scaling and translation required to support variable width.
|
||||
*
|
||||
* @param isTaskDismissal indicates if update was called due to task dismissal
|
||||
*/
|
||||
private void updateTaskSize(boolean isTaskDismissal) {
|
||||
final int taskCount = getTaskViewCount();
|
||||
if (taskCount == 0) {
|
||||
return;
|
||||
@@ -1335,7 +1359,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
mClearAllButton.setFullscreenTranslationPrimary(accumulatedTranslationX);
|
||||
|
||||
updateGridProperties();
|
||||
updateGridProperties(isTaskDismissal);
|
||||
}
|
||||
|
||||
public void getTaskSize(Rect outRect) {
|
||||
@@ -1382,13 +1406,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
|
||||
|
||||
// After scrolling, update ActionsView's visibility.
|
||||
TaskView focusedTaskView = getFocusedTaskView();
|
||||
if (focusedTaskView != null) {
|
||||
float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
|
||||
- mOrientationHandler.getPrimaryScroll(this));
|
||||
float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
|
||||
mActionsView.getScrollAlpha().setValue(Utilities.boundToRange(delta, 0, 1));
|
||||
}
|
||||
updateActionsViewScrollAlpha();
|
||||
}
|
||||
|
||||
// Update the high res thumbnail loader state
|
||||
@@ -1396,6 +1414,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return scrolling;
|
||||
}
|
||||
|
||||
private void updateActionsViewScrollAlpha() {
|
||||
float scrollAlpha = 1f;
|
||||
if (showAsGrid()) {
|
||||
TaskView focusedTaskView = getFocusedTaskView();
|
||||
if (focusedTaskView != null) {
|
||||
float scrollDiff = Math.abs(getScrollForPage(indexOfChild(focusedTaskView))
|
||||
- mOrientationHandler.getPrimaryScroll(this));
|
||||
float delta = (mGridSideMargin - scrollDiff) / (float) mGridSideMargin;
|
||||
scrollAlpha = Utilities.boundToRange(delta, 0, 1);
|
||||
}
|
||||
}
|
||||
mActionsView.getScrollAlpha().setValue(scrollAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales and adjusts translation of adjacent pages as if on a curved carousel.
|
||||
*/
|
||||
@@ -1538,7 +1570,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
setCurrentTask(-1);
|
||||
mIgnoreResetTaskId = -1;
|
||||
mTaskListChangeId = -1;
|
||||
mFocusedTaskId = -1;
|
||||
mFocusedTaskId = getTaskViewCount() > 0 ? getTaskViewAt(0).getTaskId() : -1;
|
||||
|
||||
if (mRecentsAnimationController != null) {
|
||||
if (LIVE_TILE.get() && mEnableDrawingLiveTile) {
|
||||
@@ -1579,6 +1611,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return getTaskView(mFocusedTaskId);
|
||||
}
|
||||
|
||||
protected @Nullable TaskView getHomeTaskView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the task view whose id matches {@param taskId}.
|
||||
* @return -1 if there is no task view for the task id, else the index of the task view.
|
||||
@@ -1711,11 +1747,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
setRunningTaskHidden(false);
|
||||
animateUpRunningTaskIconScale();
|
||||
|
||||
if (mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS
|
||||
&& (!showAsGrid() || getFocusedTaskView() != null)) {
|
||||
animateActionsViewIn();
|
||||
}
|
||||
animateActionsViewIn();
|
||||
|
||||
mCurrentGestureEndTarget = null;
|
||||
}
|
||||
@@ -1757,9 +1789,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
boolean runningTaskTileHidden = mRunningTaskTileHidden;
|
||||
int runningTaskId = runningTaskInfo == null ? -1 : runningTaskInfo.taskId;
|
||||
setCurrentTask(runningTaskId);
|
||||
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
|
||||
mFocusedTaskId = runningTaskId;
|
||||
}
|
||||
mFocusedTaskId = runningTaskId;
|
||||
setCurrentPage(getRunningTaskIndex());
|
||||
setRunningTaskViewShowScreenshot(false);
|
||||
setRunningTaskHidden(runningTaskTileHidden);
|
||||
@@ -1836,13 +1866,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
anim.start();
|
||||
}
|
||||
|
||||
private void animateActionsViewOut() {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(
|
||||
mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, 1, 0);
|
||||
anim.setDuration(TaskView.SCALE_ICON_DURATION);
|
||||
anim.start();
|
||||
}
|
||||
|
||||
public void animateUpRunningTaskIconScale() {
|
||||
mRunningTaskIconScaledDown = false;
|
||||
TaskView firstTask = getRunningTaskView();
|
||||
@@ -1878,17 +1901,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
|
||||
|
||||
/*
|
||||
* taskGridVerticalDiff is used to position the top of a task in the top row of the grid
|
||||
* heightOffset is the vertical space one grid task takes + space between top and
|
||||
* bottom row
|
||||
* Summed together they provide the top position for bottom row of grid tasks
|
||||
*/
|
||||
final float taskGridVerticalDiff =
|
||||
mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
|
||||
final float heightOffset =
|
||||
(mLastComputedGridTaskSize.height() + taskTopMargin) + mRowSpacing;
|
||||
|
||||
int topRowWidth = 0;
|
||||
int bottomRowWidth = 0;
|
||||
float topAccumulatedTranslationX = 0;
|
||||
@@ -1908,6 +1920,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
int snappedTaskRowWidth = 0;
|
||||
int snappedPage = getNextPage();
|
||||
TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(snappedPage);
|
||||
TaskView homeTaskView = getHomeTaskView();
|
||||
TaskView nextFocusedTaskView = null;
|
||||
|
||||
if (!isTaskDismissal) {
|
||||
mTopRowIdSet.clear();
|
||||
@@ -1945,15 +1959,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// calculate the distance focused task need to shift.
|
||||
focusedTaskShift += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
|
||||
}
|
||||
int taskId = taskView.getTask().key.id;
|
||||
int taskId = taskView.getTaskId();
|
||||
boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId)
|
||||
: topRowWidth <= bottomRowWidth;
|
||||
if (isTopRow) {
|
||||
topRowWidth += taskWidthAndSpacing;
|
||||
if (homeTaskView != null && nextFocusedTaskView == null) {
|
||||
// TaskView will be focused when swipe up, don't count towards row width.
|
||||
nextFocusedTaskView = taskView;
|
||||
} else {
|
||||
topRowWidth += taskWidthAndSpacing;
|
||||
}
|
||||
topSet.add(i);
|
||||
mTopRowIdSet.add(taskId);
|
||||
|
||||
taskView.setGridTranslationY(taskGridVerticalDiff);
|
||||
taskView.setGridTranslationY(mTaskGridVerticalDiff);
|
||||
|
||||
// Move horizontally into empty space.
|
||||
float widthOffset = 0;
|
||||
@@ -1972,7 +1991,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
bottomSet.add(i);
|
||||
|
||||
// Move into bottom row.
|
||||
taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
|
||||
taskView.setGridTranslationY(mTopBottomRowHeightDiff + mTaskGridVerticalDiff);
|
||||
|
||||
// Move horizontally into empty space.
|
||||
float widthOffset = 0;
|
||||
@@ -2031,9 +2050,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
float clearAllShorterRowCompensation =
|
||||
mIsRtl ? -shorterRowCompensation : shorterRowCompensation;
|
||||
|
||||
// If the total width is shorter than one grid's width, move ClearAllButton further away
|
||||
// accordingly. Update longRowWidth if ClearAllButton has been moved.
|
||||
float clearAllShortTotalCompensation = 0;
|
||||
int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
|
||||
if (longRowWidth < mLastComputedGridSize.width()) {
|
||||
float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
|
||||
clearAllShortTotalCompensation =
|
||||
mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
|
||||
longRowWidth = mLastComputedGridSize.width();
|
||||
}
|
||||
|
||||
float clearAllTotalTranslationX =
|
||||
clearAllAccumulatedTranslation + clearAllShorterRowCompensation
|
||||
+ snappedTaskFullscreenScrollAdjustment;
|
||||
+ clearAllShortTotalCompensation + snappedTaskFullscreenScrollAdjustment;
|
||||
if (focusedTaskIndex < taskCount) {
|
||||
// Shift by focused task's width and spacing if a task is focused.
|
||||
clearAllTotalTranslationX +=
|
||||
@@ -2043,7 +2073,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// Make sure there are enough space between snapped page and ClearAllButton, for the case
|
||||
// of swiping up after quick switch.
|
||||
if (snappedTaskView != null) {
|
||||
int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
|
||||
int distanceFromClearAll = longRowWidth - snappedTaskRowWidth;
|
||||
// ClearAllButton should be off screen when snapped task is in its snapped position.
|
||||
int minimumDistance =
|
||||
@@ -2068,8 +2097,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
if (taskView1 == null || taskView2 == null) {
|
||||
return false;
|
||||
}
|
||||
int taskId1 = taskView1.getTask().key.id;
|
||||
int taskId2 = taskView2.getTask().key.id;
|
||||
int taskId1 = taskView1.getTaskId();
|
||||
int taskId2 = taskView2.getTaskId();
|
||||
if (taskId1 == mFocusedTaskId || taskId2 == mFocusedTaskId) {
|
||||
return false;
|
||||
}
|
||||
@@ -2198,8 +2227,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
}
|
||||
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
|
||||
boolean shouldRemoveTask, long duration) {
|
||||
/**
|
||||
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
|
||||
* @param dismissedTaskView the {@link TaskView} to be dismissed
|
||||
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
|
||||
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
|
||||
* ActivityManager after dismissal
|
||||
* @param duration duration of the animation
|
||||
*/
|
||||
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView,
|
||||
boolean animateTaskView, boolean shouldRemoveTask, long duration) {
|
||||
if (mPendingAnimation != null) {
|
||||
mPendingAnimation.createPlaybackController().dispatchOnCancel();
|
||||
}
|
||||
@@ -2210,30 +2247,65 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return anim;
|
||||
}
|
||||
|
||||
boolean showAsGrid = showAsGrid();
|
||||
int taskCount = getTaskViewCount();
|
||||
int dismissedIndex = indexOfChild(dismissedTaskView);
|
||||
int dismissedTaskId = dismissedTaskView.getTaskId();
|
||||
|
||||
// Grid specific properties.
|
||||
boolean isFocusedTaskDismissed = false;
|
||||
TaskView nextFocusedTaskView = null;
|
||||
boolean nextFocusedTaskFromTop = false;
|
||||
float dismissedTaskWidth = 0;
|
||||
float nextFocusedTaskWidth = 0;
|
||||
|
||||
// Non-grid specific properties.
|
||||
int[] oldScroll = new int[count];
|
||||
int[] newScroll = new int[count];
|
||||
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
||||
getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
|
||||
int taskCount = getTaskViewCount();
|
||||
int scrollDiffPerPage = 0;
|
||||
if (count > 1) {
|
||||
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
|
||||
}
|
||||
int draggedIndex = indexOfChild(taskView);
|
||||
|
||||
boolean isFocusedTaskDismissed = taskView.getTask().key.id == mFocusedTaskId;
|
||||
if (isFocusedTaskDismissed && showAsGrid()) {
|
||||
anim.setFloat(mActionsView, VIEW_ALPHA, 0, clampToProgress(ACCEL_0_5, 0, 0.5f));
|
||||
}
|
||||
float dismissedTaskWidth = taskView.getLayoutParams().width + mPageSpacing;
|
||||
boolean needsCurveUpdates = false;
|
||||
|
||||
if (showAsGrid) {
|
||||
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
|
||||
isFocusedTaskDismissed = dismissedTaskId == mFocusedTaskId;
|
||||
if (isFocusedTaskDismissed) {
|
||||
nextFocusedTaskFromTop =
|
||||
mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
|
||||
// Pick the next focused task from the preferred row.
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (taskView == dismissedTaskView) {
|
||||
continue;
|
||||
}
|
||||
boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskId());
|
||||
if ((nextFocusedTaskFromTop && isTopRow
|
||||
|| (!nextFocusedTaskFromTop && !isTopRow))) {
|
||||
nextFocusedTaskView = taskView;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextFocusedTaskView != null) {
|
||||
nextFocusedTaskWidth =
|
||||
nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
|
||||
getPageScrolls(newScroll, false,
|
||||
v -> v.getVisibility() != GONE && v != dismissedTaskView);
|
||||
if (count > 1) {
|
||||
scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
|
||||
}
|
||||
}
|
||||
|
||||
int distanceFromDismissedTask = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child == taskView) {
|
||||
if (child == dismissedTaskView) {
|
||||
if (animateTaskView) {
|
||||
addDismissedTaskAnimations(taskView, duration, anim);
|
||||
addDismissedTaskAnimations(dismissedTaskView, duration, anim);
|
||||
}
|
||||
} else if (!showAsGrid()) {
|
||||
} else if (!showAsGrid) {
|
||||
// Compute scroll offsets from task dismissal for animation.
|
||||
// If we just take newScroll - oldScroll, everything to the right of dragged task
|
||||
// translates to the left. We need to offset this in some cases:
|
||||
@@ -2242,15 +2314,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// - Current page is rightmost page (leftmost for RTL)
|
||||
// - Dragging an adjacent page on the left side (right side for RTL)
|
||||
int offset = mIsRtl ? scrollDiffPerPage : 0;
|
||||
if (mCurrentPage == draggedIndex) {
|
||||
if (mCurrentPage == dismissedIndex) {
|
||||
int lastPage = taskCount - 1;
|
||||
if (mCurrentPage == lastPage) {
|
||||
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
|
||||
}
|
||||
} else {
|
||||
// Dragging an adjacent page.
|
||||
// Dismissing an adjacent page.
|
||||
int negativeAdjacent = mCurrentPage - 1; // (Right in RTL, left in LTR)
|
||||
if (draggedIndex == negativeAdjacent) {
|
||||
if (dismissedIndex == negativeAdjacent) {
|
||||
offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
|
||||
}
|
||||
}
|
||||
@@ -2263,28 +2335,53 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
float additionalDismissDuration =
|
||||
ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
|
||||
i - draggedIndex);
|
||||
i - dismissedIndex);
|
||||
anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR,
|
||||
Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ additionalDismissDuration, 0f, 1f), 1));
|
||||
needsCurveUpdates = true;
|
||||
}
|
||||
} else if (child instanceof TaskView) {
|
||||
TaskView taskView = (TaskView) child;
|
||||
if (isFocusedTaskDismissed) {
|
||||
if (!isSameGridRow(taskView, nextFocusedTaskView)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Animate task with index >= dismissed index and in the same row as the
|
||||
// dismissed index, or if the dismissed task was the focused task. Offset
|
||||
// successive task dismissal durations for a staggered effect.
|
||||
if (isFocusedTaskDismissed || (i >= draggedIndex && isSameGridRow((TaskView) child,
|
||||
taskView))) {
|
||||
FloatProperty translationProperty =
|
||||
((TaskView) child).getPrimaryDismissTranslationProperty();
|
||||
float additionalDismissDuration =
|
||||
ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
|
||||
i - draggedIndex);
|
||||
anim.setFloat(child, translationProperty,
|
||||
!mIsRtl ? -dismissedTaskWidth : dismissedTaskWidth,
|
||||
clampToProgress(LINEAR, Utilities.boundToRange(
|
||||
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ additionalDismissDuration, 0f, 1f), 1));
|
||||
// dismissed index or next focused index. Offset successive task dismissal
|
||||
// durations for a staggered effect.
|
||||
float animationStartProgress = Utilities.boundToRange(
|
||||
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
+ ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
|
||||
* ++distanceFromDismissedTask, 0f, 1f);
|
||||
if (taskView == nextFocusedTaskView) {
|
||||
// Enlarge the task to be focused next, and translate into focus position.
|
||||
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
|
||||
anim.setFloat(taskView, TaskView.SNAPSHOT_SCALE, scale,
|
||||
clampToProgress(LINEAR, animationStartProgress, 1f));
|
||||
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
|
||||
mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth,
|
||||
clampToProgress(LINEAR, animationStartProgress, 1f));
|
||||
float secondaryTranslation = -mTaskGridVerticalDiff;
|
||||
if (!nextFocusedTaskFromTop) {
|
||||
secondaryTranslation -= mTopBottomRowHeightDiff;
|
||||
}
|
||||
anim.setFloat(taskView, taskView.getSecondaryDissmissTranslationProperty(),
|
||||
secondaryTranslation,
|
||||
clampToProgress(LINEAR, animationStartProgress, 1f));
|
||||
anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f,
|
||||
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
|
||||
} else {
|
||||
float primaryTranslation =
|
||||
isFocusedTaskDismissed ? nextFocusedTaskWidth : dismissedTaskWidth;
|
||||
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
|
||||
mIsRtl ? primaryTranslation : -primaryTranslation,
|
||||
clampToProgress(LINEAR, animationStartProgress, 1f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2295,14 +2392,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
// Add a tiny bit of translation Z, so that it draws on top of other views
|
||||
if (animateTaskView) {
|
||||
taskView.setTranslationZ(0.1f);
|
||||
dismissedTaskView.setTranslationZ(0.1f);
|
||||
}
|
||||
|
||||
mPendingAnimation = anim;
|
||||
final TaskView finalNextFocusedTaskView = nextFocusedTaskView;
|
||||
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
|
||||
@Override
|
||||
public void accept(Boolean success) {
|
||||
if (LIVE_TILE.get() && mEnableDrawingLiveTile && taskView.isRunningTask()
|
||||
if (LIVE_TILE.get() && mEnableDrawingLiveTile && dismissedTaskView.isRunningTask()
|
||||
&& success) {
|
||||
finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
|
||||
} else {
|
||||
@@ -2314,11 +2412,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private void onEnd(boolean success) {
|
||||
if (success) {
|
||||
if (shouldRemoveTask) {
|
||||
if (taskView.getTask() != null) {
|
||||
if (dismissedTaskView.getTask() != null) {
|
||||
UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
|
||||
.removeTask(taskView.getTask().key.id));
|
||||
.removeTask(dismissedTaskId));
|
||||
mActivity.getStatsLogManager().logger()
|
||||
.withItemInfo(taskView.getItemInfo())
|
||||
.withItemInfo(dismissedTaskView.getItemInfo())
|
||||
.log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
|
||||
}
|
||||
}
|
||||
@@ -2328,31 +2426,31 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
resetTaskVisuals();
|
||||
|
||||
int pageToSnapTo = mCurrentPage;
|
||||
// Snap to start if focused task was dismissed, as after quick switch it could
|
||||
// be at any page but the focused task always displays at the start.
|
||||
if (taskView.getTask().key.id == mFocusedTaskId) {
|
||||
pageToSnapTo = mTaskViewStartIndex;
|
||||
} else if (draggedIndex < pageToSnapTo || pageToSnapTo == (getTaskViewCount()
|
||||
- 1)) {
|
||||
if (finalNextFocusedTaskView != null) {
|
||||
pageToSnapTo = indexOfChild(finalNextFocusedTaskView);
|
||||
}
|
||||
if (dismissedIndex < pageToSnapTo || pageToSnapTo == (taskCount - 1)) {
|
||||
pageToSnapTo -= 1;
|
||||
}
|
||||
removeViewInLayout(taskView);
|
||||
removeViewInLayout(dismissedTaskView);
|
||||
mTopRowIdSet.remove(dismissedTaskId);
|
||||
|
||||
if (getTaskViewCount() == 0) {
|
||||
if (taskCount == 1) {
|
||||
removeViewInLayout(mClearAllButton);
|
||||
startHome();
|
||||
} else {
|
||||
snapToPageImmediately(pageToSnapTo);
|
||||
// Grid got messed up, reapply.
|
||||
updateGridProperties(true);
|
||||
if (showAsGrid() && getFocusedTaskView() == null
|
||||
&& mActionsView.getVisibilityAlpha().getValue() == 1) {
|
||||
animateActionsViewOut();
|
||||
// Update focus task and its size.
|
||||
if (finalNextFocusedTaskView != null) {
|
||||
mFocusedTaskId = finalNextFocusedTaskView.getTaskId();
|
||||
mTopRowIdSet.remove(mFocusedTaskId);
|
||||
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
|
||||
setCurrentPage(pageToSnapTo);
|
||||
}
|
||||
updateTaskSize(true);
|
||||
// Update scroll and snap to page.
|
||||
updateScrollSynchronously();
|
||||
snapToPageImmediately(pageToSnapTo);
|
||||
}
|
||||
// Update the layout synchronously so that the position of next view is
|
||||
// immediately available.
|
||||
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
|
||||
}
|
||||
onDismissAnimationEnds();
|
||||
mPendingAnimation = null;
|
||||
@@ -2388,7 +2486,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
int taskCount = getTaskViewCount();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
TaskView taskView = getTaskViewAt(i);
|
||||
if (taskView == mSplitHiddenTaskView && taskView != getFocusedTaskView()) {
|
||||
if (taskView == mSplitHiddenTaskView
|
||||
&& !(showAsGrid() && taskView == getFocusedTaskView())) {
|
||||
// Case where the hidden task view would have overlapped w/ placeholder,
|
||||
// but because it's going to hide we don't care
|
||||
// TODO (b/187312247) edge case for thumbnails that are off screen but scroll on
|
||||
@@ -2533,7 +2632,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mContentAlpha = alpha;
|
||||
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
|
||||
TaskView child = getTaskViewAt(i);
|
||||
if (!mRunningTaskTileHidden || child.getTask().key.id != mRunningTaskId) {
|
||||
if (!mRunningTaskTileHidden || child.getTaskId() != mRunningTaskId) {
|
||||
child.setStableAlpha(alpha);
|
||||
}
|
||||
}
|
||||
@@ -3358,9 +3457,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates page scroll synchronously and layout child views.
|
||||
* Updates page scroll synchronously after measure and layout child views.
|
||||
*/
|
||||
public void updateScrollSynchronously() {
|
||||
// onMeasure is needed to update child's measured width which is used in scroll calculation,
|
||||
// in case TaskView sizes has changed when being focused/unfocused.
|
||||
onMeasure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
|
||||
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
|
||||
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
|
||||
updateMinAndMaxScrollX();
|
||||
}
|
||||
@@ -3558,6 +3661,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
public void setOverviewGridEnabled(boolean overviewGridEnabled) {
|
||||
if (mOverviewGridEnabled != overviewGridEnabled) {
|
||||
mOverviewGridEnabled = overviewGridEnabled;
|
||||
updateActionsViewScrollAlpha();
|
||||
// Request layout to ensure scroll position is recalculated with updated mGridProgress.
|
||||
requestLayout();
|
||||
}
|
||||
@@ -3695,11 +3799,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
&& mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS;
|
||||
}
|
||||
|
||||
public boolean shouldShowOverviewActionsForState(STATE_TYPE state) {
|
||||
return !state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())
|
||||
|| getFocusedTaskView() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to register callbacks for when our empty message state changes.
|
||||
*
|
||||
|
||||
@@ -166,7 +166,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
|
||||
Collections.singletonList(new Rect());
|
||||
|
||||
private static final FloatProperty<TaskView> FOCUS_TRANSITION =
|
||||
public static final FloatProperty<TaskView> FOCUS_TRANSITION =
|
||||
new FloatProperty<TaskView>("focusTransition") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
@@ -335,6 +335,19 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<TaskView> SNAPSHOT_SCALE =
|
||||
new FloatProperty<TaskView>("snapshotScale") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
taskView.setSnapshotScale(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mSnapshotView.getScaleX();
|
||||
}
|
||||
};
|
||||
|
||||
private final TaskOutlineProvider mOutlineProvider;
|
||||
|
||||
private Task mTask;
|
||||
@@ -523,8 +536,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
return mTask;
|
||||
}
|
||||
|
||||
public boolean hasTaskId(int taskId) {
|
||||
return mTask != null && mTask.key != null && mTask.key.id == taskId;
|
||||
public int getTaskId() {
|
||||
return mTask != null && mTask.key != null ? mTask.key.id : -1;
|
||||
}
|
||||
|
||||
public TaskThumbnailView getThumbnail() {
|
||||
@@ -846,6 +859,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
mSplitSelectTranslationX = 0f;
|
||||
mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY =
|
||||
mSplitSelectTranslationY = 0f;
|
||||
setSnapshotScale(1f);
|
||||
applyTranslationX();
|
||||
applyTranslationY();
|
||||
setTranslationZ(0);
|
||||
@@ -925,6 +939,9 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
|
||||
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
|
||||
setPivotY(mSnapshotView.getTop());
|
||||
mSnapshotView.setPivotX(
|
||||
getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
|
||||
mSnapshotView.setPivotY(0);
|
||||
} else {
|
||||
setPivotX((right - left) * 0.5f);
|
||||
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
|
||||
@@ -955,6 +972,11 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
return mFullscreenScale;
|
||||
}
|
||||
|
||||
private void setSnapshotScale(float dismissScale) {
|
||||
mSnapshotView.setScaleX(dismissScale);
|
||||
mSnapshotView.setScaleY(dismissScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves TaskView between carousel and 2 row grid.
|
||||
*
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/widgets_picker_surface" />
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
|
||||
android:topRightRadius="@dimen/widget_list_content_corner_radius"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/widgets_picker_surface" />
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
|
||||
android:topRightRadius="@dimen/widget_list_content_corner_radius"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/widgets_picker_surface" />
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
|
||||
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:color="?android:attr/colorControlHighlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/widgets_picker_surface" />
|
||||
<corners
|
||||
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
|
||||
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/all_apps_tabs_background"
|
||||
android:orientation="horizontal"
|
||||
android:elevation="2dp"
|
||||
style="@style/TextHeadline">
|
||||
|
||||
<Button
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="@dimen/widget_picker_view_pager_top_padding"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
launcher:pageIndicator="@+id/tabs">
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:enabled="false"
|
||||
android:clickable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:button="@drawable/widgets_tray_expand_button"/>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/all_apps_header_pill_height"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/all_apps_tabs_background"
|
||||
android:elevation="2dp"
|
||||
style="@style/TextHeadline">
|
||||
|
||||
<Button
|
||||
|
||||
@@ -146,6 +146,8 @@
|
||||
<dimen name="widget_picker_education_tip_width">120dp</dimen>
|
||||
<dimen name="widget_picker_education_tip_min_margin">4dp</dimen>
|
||||
|
||||
<dimen name="widget_picker_view_pager_top_padding">16dp</dimen>
|
||||
|
||||
<!-- Padding applied to shortcut previews -->
|
||||
<dimen name="shortcut_preview_padding_left">0dp</dimen>
|
||||
<dimen name="shortcut_preview_padding_right">0dp</dimen>
|
||||
|
||||
@@ -26,12 +26,12 @@ import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.os.Process;
|
||||
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.shadows.ShadowLooperExecutor;
|
||||
import com.android.launcher3.util.Executors;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.LauncherLayoutBuilder;
|
||||
import com.android.launcher3.util.LauncherModelHelper;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
@@ -92,7 +92,7 @@ public class ModelMultiCallbacksTest {
|
||||
// Add a new callback
|
||||
cb1.reset();
|
||||
MyCallbacks cb2 = spy(MyCallbacks.class);
|
||||
cb2.mPageToBindSync = 2;
|
||||
cb2.mPageToBindSync = IntSet.wrap(2);
|
||||
mModelHelper.getModel().addCallbacksAndLoad(cb2);
|
||||
|
||||
waitForLoaderAndTempMainThread();
|
||||
@@ -178,16 +178,16 @@ public class ModelMultiCallbacksTest {
|
||||
private abstract static class MyCallbacks implements Callbacks {
|
||||
|
||||
final List<ItemInfo> mItems = new ArrayList<>();
|
||||
int mPageToBindSync = 0;
|
||||
int mPageBoundSync = PagedView.INVALID_PAGE;
|
||||
IntSet mPageToBindSync = IntSet.wrap(0);
|
||||
IntSet mPageBoundSync = new IntSet();
|
||||
ViewOnDrawExecutor mDeferredExecutor;
|
||||
AppInfo[] mAppInfos;
|
||||
|
||||
MyCallbacks() { }
|
||||
|
||||
@Override
|
||||
public void onPageBoundSynchronously(int page) {
|
||||
mPageBoundSync = page;
|
||||
public void onPagesBoundSynchronously(IntSet pages) {
|
||||
mPageBoundSync = pages;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,13 +206,13 @@ public class ModelMultiCallbacksTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageToBindSynchronously() {
|
||||
public IntSet getPagesToBindSynchronously() {
|
||||
return mPageToBindSync;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mItems.clear();
|
||||
mPageBoundSync = PagedView.INVALID_PAGE;
|
||||
mPageBoundSync = new IntSet();
|
||||
mDeferredExecutor = null;
|
||||
mAppInfos = null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 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.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.launcher3.LauncherPageRestoreHelper;
|
||||
import com.android.launcher3.Workspace;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class LauncherPageRestoreHelperTest {
|
||||
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN_COUNT =
|
||||
"launcher.current_screen_count";
|
||||
|
||||
private LauncherPageRestoreHelper mPageRestoreHelper;
|
||||
private Bundle mState;
|
||||
|
||||
@Mock
|
||||
private Workspace mWorkspace;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
|
||||
mState = new Bundle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNoChildrenInWorkspace_whenSavePages_thenNothingSaved() {
|
||||
when(mWorkspace.getChildCount()).thenReturn(0);
|
||||
|
||||
mPageRestoreHelper.savePagesToRestore(mState);
|
||||
|
||||
assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
|
||||
assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleCurrentPages_whenSavePages_thenSavedCorrectly() {
|
||||
when(mWorkspace.getChildCount()).thenReturn(5);
|
||||
when(mWorkspace.getCurrentPage()).thenReturn(2);
|
||||
givenPanelCount(2);
|
||||
|
||||
mPageRestoreHelper.savePagesToRestore(mState);
|
||||
|
||||
assertEquals(5, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
|
||||
assertEquals(2, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNullSavedState_whenRestorePages_thenReturnEmptyIntSet() {
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(null);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTotalPageCountMissing_whenRestorePages_thenReturnEmptyIntSet() {
|
||||
givenSavedCurrentPage(1);
|
||||
givenPanelCount(1);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCurrentPageMissing_whenRestorePages_thenReturnEmptyIntSet() {
|
||||
givenSavedPageCount(3);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOnePanel_whenRestorePages_thenReturnThatPage() {
|
||||
givenSavedCurrentPage(2);
|
||||
givenSavedPageCount(5);
|
||||
givenPanelCount(1);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(2, result.getArray().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoPanelOnFirstPages_whenRestorePages_thenReturnThosePages() {
|
||||
givenSavedCurrentPage(0, 1);
|
||||
givenSavedPageCount(2);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(0, 1), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoPanelOnMiddlePages_whenRestorePages_thenReturnThosePages() {
|
||||
givenSavedCurrentPage(2, 3);
|
||||
givenSavedPageCount(5);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(2, 3), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoPanelOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
|
||||
// The device has two panel home but the current page is the last page, so we don't have
|
||||
// a right panel, only the left one.
|
||||
givenSavedCurrentPage(2);
|
||||
givenSavedPageCount(3);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(2), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOnlyOnePageAndPhoneFolding_whenRestorePages_thenReturnOnlyOnePage() {
|
||||
givenSavedCurrentPage(0);
|
||||
givenSavedPageCount(1);
|
||||
givenPanelCount(1);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(0), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPhoneFolding_whenRestorePages_thenReturnOnlyTheFirstCurrentPage() {
|
||||
givenSavedCurrentPage(2, 3);
|
||||
givenSavedPageCount(4);
|
||||
givenPanelCount(1);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(2), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPhoneUnfolding_whenRestorePages_thenReturnCurrentPagePlusTheNextOne() {
|
||||
givenSavedCurrentPage(2);
|
||||
givenSavedPageCount(4);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(2, 3), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPhoneUnfoldingOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
|
||||
givenSavedCurrentPage(4);
|
||||
givenSavedPageCount(5);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(4), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOnlyOnePageAndPhoneUnfolding_whenRestorePages_thenReturnOnlyOnePage() {
|
||||
givenSavedCurrentPage(0);
|
||||
givenSavedPageCount(1);
|
||||
givenPanelCount(2);
|
||||
|
||||
IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
|
||||
|
||||
assertEquals(IntSet.wrap(0), result);
|
||||
}
|
||||
|
||||
private void givenPanelCount(int panelCount) {
|
||||
when(mWorkspace.getPanelCount()).thenReturn(panelCount);
|
||||
when(mWorkspace.getLeftmostVisiblePageForIndex(anyInt())).thenAnswer(invocation -> {
|
||||
int pageIndex = invocation.getArgument(0);
|
||||
return pageIndex * panelCount / panelCount;
|
||||
});
|
||||
}
|
||||
|
||||
private void givenSavedPageCount(int pageCount) {
|
||||
mState.putInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, pageCount);
|
||||
}
|
||||
|
||||
private void givenSavedCurrentPage(int... pages) {
|
||||
mState.putInt(RUNTIME_STATE_CURRENT_SCREEN, pages[0]);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import com.android.launcher3.model.data.FolderInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.views.Snackbar;
|
||||
|
||||
public class DeleteDropTarget extends ButtonDropTarget {
|
||||
@@ -131,7 +132,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
|
||||
onAccessibilityDrop(null, item);
|
||||
ModelWriter modelWriter = mLauncher.getModelWriter();
|
||||
Runnable onUndoClicked = () -> {
|
||||
mLauncher.setPageToBindSynchronously(itemPage);
|
||||
mLauncher.setPagesToBindSynchronously(IntSet.wrap(itemPage));
|
||||
modelWriter.abortDelete();
|
||||
mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO);
|
||||
};
|
||||
|
||||
@@ -105,6 +105,7 @@ import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -164,6 +165,7 @@ import com.android.launcher3.util.ActivityResultInfo;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
@@ -244,8 +246,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
*/
|
||||
protected static final int REQUEST_LAST = 100;
|
||||
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE = "launcher.state";
|
||||
// Type: PendingRequestArgs
|
||||
@@ -284,6 +284,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
private WidgetManagerHelper mAppWidgetManager;
|
||||
private LauncherAppWidgetHost mAppWidgetHost;
|
||||
|
||||
private LauncherPageRestoreHelper mPageRestoreHelper;
|
||||
|
||||
private final int[] mTmpAddItemCellCoordinates = new int[2];
|
||||
|
||||
@Thunk
|
||||
@@ -319,8 +321,8 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
|
||||
private PopupDataProvider mPopupDataProvider;
|
||||
|
||||
private int mSynchronouslyBoundPage = PagedView.INVALID_PAGE;
|
||||
private int mPageToBindSynchronously = PagedView.INVALID_PAGE;
|
||||
private IntSet mSynchronouslyBoundPages = new IntSet();
|
||||
private IntSet mPagesToBindSynchronously = new IntSet();
|
||||
|
||||
// We only want to get the SharedPreferences once since it does an FS stat each time we get
|
||||
// it from the context.
|
||||
@@ -455,13 +457,10 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
restoreState(savedInstanceState);
|
||||
mStateManager.reapplyState();
|
||||
|
||||
// We only load the page synchronously if the user rotates (or triggers a
|
||||
// configuration change) while launcher is in the foreground
|
||||
int currentScreen = PagedView.INVALID_PAGE;
|
||||
mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
|
||||
if (savedInstanceState != null) {
|
||||
currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
|
||||
mPagesToBindSynchronously = mPageRestoreHelper.getPagesToRestore(savedInstanceState);
|
||||
}
|
||||
mPageToBindSynchronously = currentScreen;
|
||||
|
||||
if (!mModel.addCallbacksAndLoad(this)) {
|
||||
if (!internalStateHandled) {
|
||||
@@ -1525,18 +1524,17 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle state) {
|
||||
super.onRestoreInstanceState(state);
|
||||
mWorkspace.restoreInstanceStateForChild(mSynchronouslyBoundPage);
|
||||
if (mSynchronouslyBoundPages != null) {
|
||||
mSynchronouslyBoundPages.forEach(page -> mWorkspace.restoreInstanceStateForChild(page));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
if (mWorkspace.getChildCount() > 0) {
|
||||
outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getNextPage());
|
||||
mPageRestoreHelper.savePagesToRestore(outState);
|
||||
|
||||
}
|
||||
outState.putInt(RUNTIME_STATE, mStateManager.getState().ordinal);
|
||||
|
||||
|
||||
AbstractFloatingView widgets = AbstractFloatingView
|
||||
.getOpenView(this, AbstractFloatingView.TYPE_WIDGETS_FULL_SHEET);
|
||||
if (widgets != null) {
|
||||
@@ -2015,24 +2013,24 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the next page to bind synchronously on next bind.
|
||||
* @param page
|
||||
* Sets the next pages to bind synchronously on next bind.
|
||||
* @param pages should not be null.
|
||||
*/
|
||||
public void setPageToBindSynchronously(int page) {
|
||||
mPageToBindSynchronously = page;
|
||||
public void setPagesToBindSynchronously(@NonNull IntSet pages) {
|
||||
mPagesToBindSynchronously = pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*/
|
||||
@Override
|
||||
public int getPageToBindSynchronously() {
|
||||
if (mPageToBindSynchronously != PagedView.INVALID_PAGE) {
|
||||
return mPageToBindSynchronously;
|
||||
} else if (mWorkspace != null) {
|
||||
return mWorkspace.getCurrentPage();
|
||||
public IntSet getPagesToBindSynchronously() {
|
||||
if (mPagesToBindSynchronously != null && !mPagesToBindSynchronously.isEmpty()) {
|
||||
return mPagesToBindSynchronously;
|
||||
} else if (mWorkspace != null) {
|
||||
return mWorkspace.getVisiblePageIndices();
|
||||
} else {
|
||||
return 0;
|
||||
return new IntSet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2448,10 +2446,10 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
return info;
|
||||
}
|
||||
|
||||
public void onPageBoundSynchronously(int page) {
|
||||
mSynchronouslyBoundPage = page;
|
||||
mWorkspace.setCurrentPage(page);
|
||||
mPageToBindSynchronously = PagedView.INVALID_PAGE;
|
||||
public void onPagesBoundSynchronously(IntSet pages) {
|
||||
mSynchronouslyBoundPages = pages;
|
||||
mWorkspace.setCurrentPage(pages.getArray().get(0));
|
||||
mPagesToBindSynchronously = new IntSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2497,7 +2495,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
*
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*/
|
||||
public void finishBindingItems(int pageBoundFirst) {
|
||||
public void finishBindingItems(IntSet pagesBoundFirst) {
|
||||
Object traceToken = TraceHelper.INSTANCE.beginSection("finishBindingItems");
|
||||
mWorkspace.restoreInstanceStateForRemainingPages();
|
||||
|
||||
@@ -2512,11 +2510,13 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
ItemInstallQueue.INSTANCE.get(this)
|
||||
.resumeModelPush(FLAG_LOADER_RUNNING);
|
||||
|
||||
int currentPage = pagesBoundFirst != null && !pagesBoundFirst.isEmpty()
|
||||
? pagesBoundFirst.getArray().get(0) : PagedView.INVALID_PAGE;
|
||||
// When undoing the removal of the last item on a page, return to that page.
|
||||
// Since we are just resetting the current page without user interaction,
|
||||
// override the previous page so we don't log the page switch.
|
||||
mWorkspace.setCurrentPage(pageBoundFirst, pageBoundFirst /* overridePrevPage */);
|
||||
mPageToBindSynchronously = PagedView.INVALID_PAGE;
|
||||
mWorkspace.setCurrentPage(currentPage, currentPage /* overridePrevPage */);
|
||||
mPagesToBindSynchronously = new IntSet();
|
||||
|
||||
// Cache one page worth of icons
|
||||
getViewCache().setCacheSize(R.layout.folder_application,
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.util.IntSet;
|
||||
|
||||
import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
||||
|
||||
/**
|
||||
* There's a logic which prioritizes the binding for the current page and defers the other pages'
|
||||
* binding. If two panel home is enabled, we want to bind both pages together.
|
||||
* LauncherPageRestoreHelper's purpose is to contain the logic for persisting, restoring and
|
||||
* calculating which pages to load immediately.
|
||||
*/
|
||||
public class LauncherPageRestoreHelper {
|
||||
|
||||
public static final String TAG = "LauncherPageRestoreHelper";
|
||||
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
|
||||
// Type: int
|
||||
private static final String RUNTIME_STATE_CURRENT_SCREEN_COUNT =
|
||||
"launcher.current_screen_count";
|
||||
|
||||
private Workspace mWorkspace;
|
||||
|
||||
public LauncherPageRestoreHelper(Workspace workspace) {
|
||||
this.mWorkspace = workspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some configuration changes trigger Launcher to recreate itself, and we want to give more
|
||||
* priority to the currently active pages in the restoration process.
|
||||
*/
|
||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
||||
public IntSet getPagesToRestore(Bundle savedInstanceState) {
|
||||
IntSet pagesToRestore = new IntSet();
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
return pagesToRestore;
|
||||
}
|
||||
|
||||
int currentPage = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
|
||||
int totalPageCount = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, -1);
|
||||
int panelCount = mWorkspace.getPanelCount();
|
||||
|
||||
if (totalPageCount <= 0 || currentPage < 0) {
|
||||
Log.e(TAG, "getPagesToRestore: Invalid input: " + totalPageCount + ", " + currentPage);
|
||||
return pagesToRestore;
|
||||
}
|
||||
|
||||
int newCurrentPage = mWorkspace.getLeftmostVisiblePageForIndex(currentPage);
|
||||
for (int page = newCurrentPage; page < newCurrentPage + panelCount
|
||||
&& page < totalPageCount; page++) {
|
||||
pagesToRestore.add(page);
|
||||
}
|
||||
|
||||
return pagesToRestore;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be called from Launcher's onSaveInstanceState method to persist everything that
|
||||
* is necessary to calculate later which pages need to be initialized first after a
|
||||
* configuration change.
|
||||
*/
|
||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
||||
public void savePagesToRestore(Bundle outState) {
|
||||
int pageCount = mWorkspace.getChildCount();
|
||||
if (pageCount > 0) {
|
||||
outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentPage());
|
||||
outState.putInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, pageCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
||||
import static com.android.launcher3.anim.Interpolators.SCROLL;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
|
||||
@@ -48,6 +49,7 @@ import android.widget.OverScroller;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -55,6 +57,7 @@ import com.android.launcher3.pageindicators.PageIndicator;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler.ChildBounds;
|
||||
import com.android.launcher3.util.EdgeEffectCompat;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
@@ -282,9 +285,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
return newPage;
|
||||
}
|
||||
|
||||
private int getLeftmostVisiblePageForIndex(int pageIndex) {
|
||||
/**
|
||||
* In most cases where panelCount is 1, this method will just return the page index that was
|
||||
* passed in.
|
||||
* But for example when two panel home is enabled we might need the leftmost visible page index
|
||||
* because that page is the current page.
|
||||
*/
|
||||
public int getLeftmostVisiblePageForIndex(int pageIndex) {
|
||||
int panelCount = getPanelCount();
|
||||
return (pageIndex / panelCount) * panelCount;
|
||||
return pageIndex - pageIndex % panelCount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,17 +303,35 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an IntSet with the indices of the currently visible pages
|
||||
*/
|
||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
||||
public IntSet getVisiblePageIndices() {
|
||||
IntSet visiblePageIndices = new IntSet();
|
||||
int panelCount = getPanelCount();
|
||||
int pageCount = getPageCount();
|
||||
|
||||
// If a device goes from one panel to two panel (i.e. unfolding a foldable device) while
|
||||
// an odd indexed page is the current page, then the new leftmost visible page will be
|
||||
// different from the old mCurrentPage.
|
||||
int currentPage = getLeftmostVisiblePageForIndex(mCurrentPage);
|
||||
for (int page = currentPage; page < currentPage + panelCount && page < pageCount; page++) {
|
||||
visiblePageIndices.add(page);
|
||||
}
|
||||
return visiblePageIndices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the callback against each visible page
|
||||
*/
|
||||
public void forEachVisiblePage(Consumer<View> callback) {
|
||||
int panelCount = getPanelCount();
|
||||
for (int i = mCurrentPage; i < mCurrentPage + panelCount; i++) {
|
||||
View page = getPageAt(i);
|
||||
getVisiblePageIndices().forEach(pageIndex -> {
|
||||
View page = getPageAt(pageIndex);
|
||||
if (page != null) {
|
||||
callback.accept(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static androidx.annotation.VisibleForTesting.PROTECTED;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
@@ -63,6 +64,8 @@ import android.view.ViewTreeObserver;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
|
||||
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
@@ -461,7 +464,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPanelCount() {
|
||||
@VisibleForTesting(otherwise = PROTECTED)
|
||||
public int getPanelCount() {
|
||||
return isTwoPanelEnabled() ? 2 : super.getPanelCount();
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ public final class FeatureFlags {
|
||||
"Uses two panel on home screen. Only applicable on large screen devices.");
|
||||
|
||||
public static final BooleanFlag ENABLE_SPLIT_SELECT = getDebugFlag(
|
||||
"ENABLE_SPLIT_SELECT", false, "Uses new split screen selection overview UI");
|
||||
"ENABLE_SPLIT_SELECT", true, "Uses new split screen selection overview UI");
|
||||
|
||||
public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag(
|
||||
"ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets");
|
||||
|
||||
@@ -79,6 +79,7 @@ import com.android.launcher3.uioverrides.PredictedAppIconInflater;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
@@ -391,11 +392,14 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
|
||||
ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
|
||||
ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
|
||||
filterCurrentWorkspaceItems(0 /* currentScreenId */,
|
||||
dataModel.workspaceItems, currentWorkspaceItems,
|
||||
otherWorkspaceItems);
|
||||
filterCurrentWorkspaceItems(0 /* currentScreenId */, dataModel.appWidgets,
|
||||
currentAppWidgets, otherAppWidgets);
|
||||
|
||||
IntSet currentScreenIds = IntSet.wrap(0);
|
||||
// TODO(b/185508060): support two panel preview.
|
||||
filterCurrentWorkspaceItems(currentScreenIds, dataModel.workspaceItems,
|
||||
currentWorkspaceItems, otherWorkspaceItems);
|
||||
filterCurrentWorkspaceItems(currentScreenIds, dataModel.appWidgets, currentAppWidgets,
|
||||
otherAppWidgets);
|
||||
|
||||
sortWorkspaceItemsSpatially(mIdp, currentWorkspaceItems);
|
||||
for (ItemInfo itemInfo : currentWorkspaceItems) {
|
||||
switch (itemInfo.itemType) {
|
||||
|
||||
@@ -24,13 +24,13 @@ import android.util.Log;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel.CallbackTask;
|
||||
import com.android.launcher3.PagedView;
|
||||
import com.android.launcher3.model.BgDataModel.Callbacks;
|
||||
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.LooperIdleLock;
|
||||
import com.android.launcher3.util.ViewOnDrawExecutor;
|
||||
@@ -160,20 +160,26 @@ public abstract class BaseLoaderResults {
|
||||
}
|
||||
|
||||
private void bind() {
|
||||
final int currentScreen;
|
||||
IntSet currentScreenIndices;
|
||||
{
|
||||
// Create an anonymous scope to calculate currentScreen as it has to be a
|
||||
// final variable.
|
||||
int currScreen = mCallbacks.getPageToBindSynchronously();
|
||||
if (currScreen >= mOrderedScreenIds.size()) {
|
||||
// There may be no workspace screens (just hotseat items and an empty page).
|
||||
currScreen = PagedView.INVALID_PAGE;
|
||||
IntSet screenIndices = mCallbacks.getPagesToBindSynchronously();
|
||||
if (screenIndices == null || screenIndices.isEmpty()
|
||||
|| screenIndices.getArray().get(screenIndices.size() - 1)
|
||||
>= mOrderedScreenIds.size()) {
|
||||
// There maybe no workspace screens (just hotseat items and an empty page).
|
||||
// Also we want to prevent IndexOutOfBoundsExceptions.
|
||||
screenIndices = new IntSet();
|
||||
}
|
||||
currentScreen = currScreen;
|
||||
currentScreenIndices = screenIndices;
|
||||
}
|
||||
final boolean validFirstPage = currentScreen >= 0;
|
||||
final int currentScreenId =
|
||||
validFirstPage ? mOrderedScreenIds.get(currentScreen) : INVALID_SCREEN_ID;
|
||||
|
||||
final boolean validFirstPage = !currentScreenIndices.isEmpty();
|
||||
|
||||
IntSet currentScreenIds = new IntSet();
|
||||
currentScreenIndices.forEach(
|
||||
index -> currentScreenIds.add(mOrderedScreenIds.get(index)));
|
||||
|
||||
// Separate the items that are on the current screen, and all the other remaining items
|
||||
ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
|
||||
@@ -181,9 +187,9 @@ public abstract class BaseLoaderResults {
|
||||
ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
|
||||
ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
|
||||
|
||||
filterCurrentWorkspaceItems(currentScreenId, mWorkspaceItems, currentWorkspaceItems,
|
||||
filterCurrentWorkspaceItems(currentScreenIds, mWorkspaceItems, currentWorkspaceItems,
|
||||
otherWorkspaceItems);
|
||||
filterCurrentWorkspaceItems(currentScreenId, mAppWidgets, currentAppWidgets,
|
||||
filterCurrentWorkspaceItems(currentScreenIds, mAppWidgets, currentAppWidgets,
|
||||
otherAppWidgets);
|
||||
final InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile();
|
||||
sortWorkspaceItemsSpatially(idp, currentWorkspaceItems);
|
||||
@@ -220,14 +226,14 @@ public abstract class BaseLoaderResults {
|
||||
bindWorkspaceItems(otherWorkspaceItems, deferredExecutor);
|
||||
bindAppWidgets(otherAppWidgets, deferredExecutor);
|
||||
// Tell the workspace that we're done binding items
|
||||
executeCallbacksTask(c -> c.finishBindingItems(currentScreen), deferredExecutor);
|
||||
executeCallbacksTask(c -> c.finishBindingItems(currentScreenIndices), deferredExecutor);
|
||||
|
||||
if (validFirstPage) {
|
||||
executeCallbacksTask(c -> {
|
||||
// We are loading synchronously, which means, some of the pages will be
|
||||
// bound after first draw. Inform the mCallbacks that page binding is
|
||||
// not complete, and schedule the remaining pages.
|
||||
c.onPageBoundSynchronously(currentScreen);
|
||||
c.onPagesBoundSynchronously(currentScreenIndices);
|
||||
c.executeOnNextDraw((ViewOnDrawExecutor) deferredExecutor);
|
||||
|
||||
}, mUiExecutor);
|
||||
|
||||
@@ -446,15 +446,16 @@ public class BgDataModel {
|
||||
int FLAG_QUIET_MODE_CHANGE_PERMISSION = 1 << 2;
|
||||
|
||||
/**
|
||||
* Returns the page number to bind first, synchronously if possible or -1
|
||||
* Returns an IntSet of page numbers to bind first, synchronously if possible
|
||||
* or an empty IntSet
|
||||
*/
|
||||
int getPageToBindSynchronously();
|
||||
IntSet getPagesToBindSynchronously();
|
||||
void clearPendingBinds();
|
||||
void startBinding();
|
||||
void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons);
|
||||
void bindScreens(IntArray orderedScreenIds);
|
||||
void finishFirstPageBind(ViewOnDrawExecutor executor);
|
||||
void finishBindingItems(int pageBoundFirst);
|
||||
void finishBindingItems(IntSet pagesBoundFirst);
|
||||
void preAddApps();
|
||||
void bindAppsAdded(IntArray newScreens,
|
||||
ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated);
|
||||
@@ -468,7 +469,7 @@ public class BgDataModel {
|
||||
void bindRestoreItemsChange(HashSet<ItemInfo> updates);
|
||||
void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);
|
||||
void bindAllWidgets(List<WidgetsListBaseEntry> widgets);
|
||||
void onPageBoundSynchronously(int page);
|
||||
void onPagesBoundSynchronously(IntSet pages);
|
||||
void executeOnNextDraw(ViewOnDrawExecutor executor);
|
||||
void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap);
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IOUtils;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.LooperIdleLock;
|
||||
import com.android.launcher3.util.PackageManagerHelper;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
@@ -173,8 +174,9 @@ public class LoaderTask implements Runnable {
|
||||
ArrayList<ItemInfo> allItems = mBgDataModel.getAllWorkspaceItems();
|
||||
// Screen set is never empty
|
||||
final int firstScreen = mBgDataModel.collectWorkspaceScreens().get(0);
|
||||
// TODO(b/185515153): support two panel home.
|
||||
|
||||
filterCurrentWorkspaceItems(firstScreen, allItems, firstScreenItems,
|
||||
filterCurrentWorkspaceItems(IntSet.wrap(firstScreen), allItems, firstScreenItems,
|
||||
new ArrayList<>() /* otherScreenItems are ignored */);
|
||||
mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ public class ModelUtils {
|
||||
* Filters the set of items who are directly or indirectly (via another container) on the
|
||||
* specified screen.
|
||||
*/
|
||||
public static <T extends ItemInfo> void filterCurrentWorkspaceItems(int currentScreenId,
|
||||
public static <T extends ItemInfo> void filterCurrentWorkspaceItems(
|
||||
IntSet currentScreenIds,
|
||||
ArrayList<T> allWorkspaceItems,
|
||||
ArrayList<T> currentScreenItems,
|
||||
ArrayList<T> otherScreenItems) {
|
||||
@@ -65,7 +66,7 @@ public class ModelUtils {
|
||||
(lhs, rhs) -> Integer.compare(lhs.container, rhs.container));
|
||||
for (T info : allWorkspaceItems) {
|
||||
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
|
||||
if (info.screenId == currentScreenId) {
|
||||
if (currentScreenIds.contains(info.screenId)) {
|
||||
currentScreenItems.add(info);
|
||||
itemsOnScreen.add(info.id);
|
||||
} else {
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.popup.PopupDataProvider;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.ViewOnDrawExecutor;
|
||||
@@ -175,8 +176,8 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageToBindSynchronously() {
|
||||
return 0;
|
||||
public IntSet getPagesToBindSynchronously() {
|
||||
return new IntSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,7 +200,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishBindingItems(int pageBoundFirst) { }
|
||||
public void finishBindingItems(IntSet pagesBoundFirst) { }
|
||||
|
||||
@Override
|
||||
public void preAddApps() { }
|
||||
@@ -229,7 +230,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity
|
||||
public void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
|
||||
|
||||
@Override
|
||||
public void onPageBoundSynchronously(int page) { }
|
||||
public void onPagesBoundSynchronously(IntSet pages) { }
|
||||
|
||||
@Override
|
||||
public void executeOnNextDraw(ViewOnDrawExecutor executor) {
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Copy of the platform hidden implementation of android.util.IntArray.
|
||||
* Implements a growing array of int primitives.
|
||||
*/
|
||||
public class IntArray implements Cloneable {
|
||||
public class IntArray implements Cloneable, Iterable<Integer> {
|
||||
private static final int MIN_CAPACITY_INCREMENT = 12;
|
||||
|
||||
private static final int[] EMPTY_INT = new int[0];
|
||||
@@ -272,4 +273,30 @@ public class IntArray implements Cloneable {
|
||||
throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
|
||||
@Thunk
|
||||
class ValueIterator implements Iterator<Integer> {
|
||||
|
||||
private int mNextIndex = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return mNextIndex < size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
return get(mNextIndex++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,13 @@
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A wrapper over IntArray implementing a growing set of int primitives.
|
||||
* The elements in the array are sorted in ascending order.
|
||||
*/
|
||||
public class IntSet {
|
||||
public class IntSet implements Iterable<Integer> {
|
||||
|
||||
final IntArray mArray = new IntArray();
|
||||
|
||||
@@ -34,6 +36,16 @@ public class IntSet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified value from the set if it exist.
|
||||
*/
|
||||
public void remove(int value) {
|
||||
int index = Arrays.binarySearch(mArray.mValues, 0, mArray.mSize, value);
|
||||
if (index >= 0) {
|
||||
mArray.removeIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int value) {
|
||||
return Arrays.binarySearch(mArray.mValues, 0, mArray.mSize, value) >= 0;
|
||||
}
|
||||
@@ -61,6 +73,9 @@ public class IntSet {
|
||||
return (obj instanceof IntSet) && ((IntSet) obj).mArray.equals(mArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped IntArray. The elements in the array are sorted in ascending order.
|
||||
*/
|
||||
public IntArray getArray() {
|
||||
return mArray;
|
||||
}
|
||||
@@ -78,4 +93,21 @@ public class IntSet {
|
||||
Arrays.sort(set.mArray.mValues, 0, set.mArray.mSize);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an IntSet with the given values.
|
||||
*/
|
||||
public static IntSet wrap(int... array) {
|
||||
return wrap(IntArray.wrap(array));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return mArray.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntSet{" + mArray.toConcatString() + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
}
|
||||
};
|
||||
private final int mTabsHeight;
|
||||
private final int mViewPagerTopPadding;
|
||||
private final int mWidgetCellHorizontalPadding;
|
||||
|
||||
@Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
|
||||
@@ -148,6 +149,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
? getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
|
||||
: 0;
|
||||
mViewPagerTopPadding = mHasWorkProfile
|
||||
? getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.widget_picker_view_pager_top_padding)
|
||||
: 0;
|
||||
mWidgetCellHorizontalPadding = 2 * getResources().getDimensionPixelOffset(
|
||||
R.dimen.widget_cell_horizontal_padding);
|
||||
}
|
||||
@@ -499,8 +504,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
noWidgetsViewHeight = noWidgetsViewTextBounds.height();
|
||||
}
|
||||
float maxTableHeight = (mActivityContext.getDeviceProfile().availableHeightPx
|
||||
- mTabsHeight - getHeaderViewHeight() - noWidgetsViewHeight)
|
||||
* RECOMMENDATION_TABLE_HEIGHT_RATIO;
|
||||
- mTabsHeight - mViewPagerTopPadding - getHeaderViewHeight()
|
||||
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
|
||||
|
||||
List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
|
||||
WidgetsTableUtils.groupWidgetItemsIntoTable(recommendedWidgets,
|
||||
@@ -605,7 +610,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
return measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mCollapseHandle)
|
||||
+ measureHeightWithVerticalMargins(mSearchAndRecommendationViewHolder.mHeaderTitle)
|
||||
+ measureHeightWithVerticalMargins(
|
||||
(View) mSearchAndRecommendationViewHolder.mSearchBar);
|
||||
(View) mSearchAndRecommendationViewHolder.mSearchBarContainer);
|
||||
}
|
||||
|
||||
/** private the height, in pixel, + the vertical margins of a given view. */
|
||||
|
||||
Reference in New Issue
Block a user