Search in sources :

Example 21 with OVERVIEW

use of com.android.launcher3.LauncherState.OVERVIEW in project android_packages_apps_Launcher3 by AOSPA.

the class RecentsView method updateGridProperties.

/**
 * Updates TaskView and ClearAllButton scaling and translation required to turn into grid
 * layout.
 *
 * This method only calculates the potential position and depends on {@link #setGridProgress} to
 * apply the actual scaling and translation.
 *
 * @param isTaskDismissal    indicates if update was called due to task dismissal
 * @param startRebalanceAfter which view index to start rebalancing from. Use Integer.MAX_VALUE
 *                           to skip rebalance
 */
private void updateGridProperties(boolean isTaskDismissal, int startRebalanceAfter) {
    int taskCount = getTaskViewCount();
    if (taskCount == 0) {
        return;
    }
    int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
    int topRowWidth = 0;
    int bottomRowWidth = 0;
    float topAccumulatedTranslationX = 0;
    float bottomAccumulatedTranslationX = 0;
    // Contains whether the child index is in top or bottom of grid (for non-focused task)
    // Different from mTopRowIdSet, which contains the taskViewId of what task is in top row
    IntSet topSet = new IntSet();
    IntSet bottomSet = new IntSet();
    // Horizontal grid translation for each task
    float[] gridTranslations = new float[taskCount];
    int focusedTaskIndex = Integer.MAX_VALUE;
    int focusedTaskShift = 0;
    int focusedTaskWidthAndSpacing = 0;
    int snappedTaskRowWidth = 0;
    int snappedPage = getNextPage();
    TaskView snappedTaskView = getTaskViewAt(snappedPage);
    TaskView homeTaskView = getHomeTaskView();
    TaskView nextFocusedTaskView = null;
    if (!isTaskDismissal) {
        mTopRowIdSet.clear();
    }
    for (int i = 0; i < taskCount; i++) {
        TaskView taskView = requireTaskViewAt(i);
        int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
        // the grid.
        if (taskView.isFocusedTask()) {
            topRowWidth += taskWidthAndSpacing;
            bottomRowWidth += taskWidthAndSpacing;
            focusedTaskIndex = i;
            focusedTaskWidthAndSpacing = taskWidthAndSpacing;
            gridTranslations[i] += focusedTaskShift;
            gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
            // Center view vertically in case it's from different orientation.
            taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin - taskView.getLayoutParams().height) / 2f);
            if (taskView == snappedTaskView) {
                // If focused task is snapped, the row width is just task width and spacing.
                snappedTaskRowWidth = taskWidthAndSpacing;
            }
        } else {
            if (i > focusedTaskIndex) {
                // For tasks after the focused task, shift by focused task's width and spacing.
                gridTranslations[i] += mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
            } else {
                // For task before the focused task, accumulate the width and spacing to
                // calculate the distance focused task need to shift.
                focusedTaskShift += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
            }
            int taskViewId = taskView.getTaskViewId();
            // Rebalance the grid starting after a certain index
            boolean isTopRow;
            if (isTaskDismissal) {
                if (i > startRebalanceAfter) {
                    mTopRowIdSet.remove(taskViewId);
                    isTopRow = topRowWidth <= bottomRowWidth;
                } else {
                    isTopRow = mTopRowIdSet.contains(taskViewId);
                }
            } else {
                isTopRow = topRowWidth <= bottomRowWidth;
            }
            if (isTopRow) {
                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(taskViewId);
                taskView.setGridTranslationY(mTaskGridVerticalDiff);
                // Move horizontally into empty space.
                float widthOffset = 0;
                for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
                    if (j == focusedTaskIndex) {
                        continue;
                    }
                    widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                }
                float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
                gridTranslations[i] += topAccumulatedTranslationX + currentTaskTranslationX;
                topAccumulatedTranslationX += currentTaskTranslationX;
            } else {
                bottomRowWidth += taskWidthAndSpacing;
                bottomSet.add(i);
                // Move into bottom row.
                taskView.setGridTranslationY(mTopBottomRowHeightDiff + mTaskGridVerticalDiff);
                // Move horizontally into empty space.
                float widthOffset = 0;
                for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
                    if (j == focusedTaskIndex) {
                        continue;
                    }
                    widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                }
                float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
                gridTranslations[i] += bottomAccumulatedTranslationX + currentTaskTranslationX;
                bottomAccumulatedTranslationX += currentTaskTranslationX;
            }
            if (taskView == snappedTaskView) {
                snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
            }
        }
    }
    // We need to maintain snapped task's page scroll invariant between quick switch and
    // overview, so we sure snapped task's grid translation is 0, and add a non-fullscreen
    // translationX that is the same as snapped task's full scroll adjustment.
    float snappedTaskNonGridScrollAdjustment = 0;
    float snappedTaskGridTranslationX = 0;
    if (snappedTaskView != null) {
        snappedTaskNonGridScrollAdjustment = snappedTaskView.getScrollAdjustment(/*fullscreenEnabled=*/
        true, /*gridEnabled=*/
        false);
        snappedTaskGridTranslationX = gridTranslations[snappedPage];
    }
    // Use the accumulated translation of the row containing the last task.
    float clearAllAccumulatedTranslation = topSet.contains(taskCount - 1) ? topAccumulatedTranslationX : bottomAccumulatedTranslationX;
    // If the last task is on the shorter row, ClearAllButton will embed into the shorter row
    // which is not what we want. Compensate the width difference of the 2 rows in that case.
    float shorterRowCompensation = 0;
    if (topRowWidth <= bottomRowWidth) {
        if (topSet.contains(taskCount - 1)) {
            shorterRowCompensation = bottomRowWidth - topRowWidth;
        }
    } else {
        if (bottomSet.contains(taskCount - 1)) {
            shorterRowCompensation = topRowWidth - bottomRowWidth;
        }
    }
    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 + clearAllShortTotalCompensation + snappedTaskNonGridScrollAdjustment;
    if (focusedTaskIndex < taskCount) {
        // Shift by focused task's width and spacing if a task is focused.
        clearAllTotalTranslationX += mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
    }
    // of swiping up after quick switch.
    if (snappedTaskView != null) {
        int distanceFromClearAll = longRowWidth - snappedTaskRowWidth + mPageSpacing;
        // ClearAllButton should be off screen when snapped task is in its snapped position.
        int minimumDistance = mTaskWidth - snappedTaskView.getLayoutParams().width + (mLastComputedGridSize.width() - mTaskWidth) / 2;
        if (distanceFromClearAll < minimumDistance) {
            int distanceDifference = minimumDistance - distanceFromClearAll;
            snappedTaskGridTranslationX += mIsRtl ? distanceDifference : -distanceDifference;
        }
    }
    for (int i = 0; i < taskCount; i++) {
        TaskView taskView = requireTaskViewAt(i);
        taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX + snappedTaskNonGridScrollAdjustment);
    }
    mClearAllButton.setGridTranslationPrimary(clearAllTotalTranslationX - snappedTaskGridTranslationX);
    mClearAllButton.setGridScrollOffset(mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left : mLastComputedTaskSize.right - mLastComputedGridSize.right);
    setGridProgress(mGridProgress);
}
Also used : IntSet(com.android.launcher3.util.IntSet) TextPaint(android.text.TextPaint) Point(android.graphics.Point)

Example 22 with OVERVIEW

use of com.android.launcher3.LauncherState.OVERVIEW in project android_packages_apps_Launcher3 by AOSPA.

the class TaplTestsQuickstep method testBackground.

@Test
@NavigationModeSwitch
@PortraitLandscape
public void testBackground() throws Exception {
    startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
    final Background background = getAndAssertBackground();
    assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
    assertTrue("Launcher internal state didn't switch to Overview", isInState(() -> LauncherState.OVERVIEW));
}
Also used : Background(com.android.launcher3.tapl.Background) LargeTest(androidx.test.filters.LargeTest) Test(org.junit.Test) NavigationModeSwitch(com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch)

Example 23 with OVERVIEW

use of com.android.launcher3.LauncherState.OVERVIEW in project android_packages_apps_Launcher3 by AOSPA.

the class RecentsView method createTaskLaunchAnimation.

public PendingAnimation createTaskLaunchAnimation(TaskView tv, long duration, Interpolator interpolator) {
    if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
        throw new IllegalStateException("Another pending animation is still running");
    }
    int count = getTaskViewCount();
    if (count == 0) {
        return new PendingAnimation(duration);
    }
    // When swiping down from overview to tasks, ensures the snapped page's scroll maintain
    // invariant between quick switch and overview, to ensure a smooth animation transition.
    updateGridProperties();
    updateScrollSynchronously();
    int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
    final boolean[] passedOverviewThreshold = new boolean[] { false };
    ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
    progressAnim.addUpdateListener(animator -> {
        // tasks' flags
        if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
            mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
        } else {
            mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
        }
        // Passing the threshold from taskview to fullscreen app will vibrate
        final boolean passed = animator.getAnimatedFraction() >= SUCCESS_TRANSITION_PROGRESS;
        if (passed != passedOverviewThreshold[0]) {
            passedOverviewThreshold[0] = passed;
            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
        }
    });
    AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
    DepthController depthController = getDepthController();
    if (depthController != null) {
        ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(mActivity));
        anim.play(depthAnimator);
    }
    anim.play(progressAnim);
    anim.setInterpolator(interpolator);
    mPendingAnimation = new PendingAnimation(duration);
    mPendingAnimation.add(anim);
    if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
        runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator().addOverviewToAppAnim(mPendingAnimation, interpolator));
        mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
    }
    mPendingAnimation.addEndListener(isSuccess -> {
        if (isSuccess) {
            if (tv.getTaskIds()[1] != -1) {
                // TODO(b/194414938): make this part of the animations instead.
                TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps, true, /*shown*/
                false);
            }
            if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
                finishRecentsAnimation(false, /* toRecents */
                null);
                onTaskLaunchAnimationEnd(true);
            } else {
                tv.launchTask(this::onTaskLaunchAnimationEnd);
            }
            Task task = tv.getTask();
            if (task != null) {
                mActivity.getStatsLogManager().logger().withItemInfo(tv.getItemInfo()).log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
            }
        } else {
            onTaskLaunchAnimationEnd(false);
        }
        mPendingAnimation = null;
    });
    return mPendingAnimation;
}
Also used : PendingAnimation(com.android.launcher3.anim.PendingAnimation) Task(com.android.systemui.shared.recents.model.Task) GroupTask(com.android.quickstep.util.GroupTask) ObjectAnimator(android.animation.ObjectAnimator) AnimatorSet(android.animation.AnimatorSet) ValueAnimator(android.animation.ValueAnimator) DepthController(com.android.launcher3.statehandlers.DepthController) TextPaint(android.text.TextPaint) Point(android.graphics.Point)

Example 24 with OVERVIEW

use of com.android.launcher3.LauncherState.OVERVIEW in project android_packages_apps_Launcher3 by AOSPA.

the class TaskViewUtils method findTaskViewToLaunch.

/**
 * Try to find a TaskView that corresponds with the component of the launched view.
 *
 * If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation.
 * Otherwise, we will assume we are using a normal app transition, but it's possible that the
 * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
 */
public static TaskView findTaskViewToLaunch(RecentsView recentsView, View v, RemoteAnimationTargetCompat[] targets) {
    if (v instanceof TaskView) {
        TaskView taskView = (TaskView) v;
        return recentsView.isTaskViewVisible(taskView) ? taskView : null;
    }
    // the task id of the opening task and see if we can find a match.
    if (v.getTag() instanceof ItemInfo) {
        ItemInfo itemInfo = (ItemInfo) v.getTag();
        ComponentName componentName = itemInfo.getTargetComponent();
        int userId = itemInfo.user.getIdentifier();
        if (componentName != null) {
            for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
                TaskView taskView = recentsView.getTaskViewAt(i);
                if (recentsView.isTaskViewVisible(taskView)) {
                    Task.TaskKey key = taskView.getTask().key;
                    if (componentName.equals(key.getComponent()) && userId == key.userId) {
                        return taskView;
                    }
                }
            }
        }
    }
    if (targets == null) {
        return null;
    }
    // Resolve the opening task id
    int openingTaskId = -1;
    for (RemoteAnimationTargetCompat target : targets) {
        if (target.mode == MODE_OPENING) {
            openingTaskId = target.taskId;
            break;
        }
    }
    // If there is no opening task id, fall back to the normal app icon launch animation
    if (openingTaskId == -1) {
        return null;
    }
    // If the opening task id is not currently visible in overview, then fall back to normal app
    // icon launch animation
    TaskView taskView = recentsView.getTaskViewByTaskId(openingTaskId);
    if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
        return null;
    }
    return taskView;
}
Also used : GroupedTaskView(com.android.quickstep.views.GroupedTaskView) TaskView(com.android.quickstep.views.TaskView) Task(com.android.systemui.shared.recents.model.Task) ItemInfo(com.android.launcher3.model.data.ItemInfo) RemoteAnimationTargetCompat(com.android.systemui.shared.system.RemoteAnimationTargetCompat) ComponentName(android.content.ComponentName)

Example 25 with OVERVIEW

use of com.android.launcher3.LauncherState.OVERVIEW in project android_packages_apps_Trebuchet by LineageOS.

the class TaskViewUtils method findTaskViewToLaunch.

/**
 * Try to find a TaskView that corresponds with the component of the launched view.
 *
 * If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation.
 * Otherwise, we will assume we are using a normal app transition, but it's possible that the
 * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
 */
public static TaskView findTaskViewToLaunch(BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
    RecentsView recentsView = activity.getOverviewPanel();
    if (v instanceof TaskView) {
        TaskView taskView = (TaskView) v;
        return recentsView.isTaskViewVisible(taskView) ? taskView : null;
    }
    // the task id of the opening task and see if we can find a match.
    if (v.getTag() instanceof ItemInfo) {
        ItemInfo itemInfo = (ItemInfo) v.getTag();
        ComponentName componentName = itemInfo.getTargetComponent();
        int userId = itemInfo.user.getIdentifier();
        if (componentName != null) {
            for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
                TaskView taskView = recentsView.getTaskViewAt(i);
                if (recentsView.isTaskViewVisible(taskView)) {
                    Task.TaskKey key = taskView.getTask().key;
                    if (componentName.equals(key.getComponent()) && userId == key.userId) {
                        return taskView;
                    }
                }
            }
        }
    }
    if (targets == null) {
        return null;
    }
    // Resolve the opening task id
    int openingTaskId = -1;
    for (RemoteAnimationTargetCompat target : targets) {
        if (target.mode == MODE_OPENING) {
            openingTaskId = target.taskId;
            break;
        }
    }
    // If there is no opening task id, fall back to the normal app icon launch animation
    if (openingTaskId == -1) {
        return null;
    }
    // If the opening task id is not currently visible in overview, then fall back to normal app
    // icon launch animation
    TaskView taskView = recentsView.getTaskView(openingTaskId);
    if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
        return null;
    }
    return taskView;
}
Also used : TaskView(com.android.quickstep.views.TaskView) Task(com.android.systemui.shared.recents.model.Task) ItemInfo(com.android.launcher3.model.data.ItemInfo) RemoteAnimationTargetCompat(com.android.systemui.shared.system.RemoteAnimationTargetCompat) RecentsView(com.android.quickstep.views.RecentsView) ComponentName(android.content.ComponentName)

Aggregations

LauncherState (com.android.launcher3.LauncherState)53 Animator (android.animation.Animator)50 ValueAnimator (android.animation.ValueAnimator)42 StateAnimationConfig (com.android.launcher3.states.StateAnimationConfig)41 RecentsView (com.android.quickstep.views.RecentsView)40 AnimatorSet (android.animation.AnimatorSet)38 Launcher (com.android.launcher3.Launcher)36 AnimatorListenerAdapter (android.animation.AnimatorListenerAdapter)34 ObjectAnimator (android.animation.ObjectAnimator)30 LargeTest (androidx.test.filters.LargeTest)29 Test (org.junit.Test)29 Point (android.graphics.Point)24 View (android.view.View)22 DeviceProfile (com.android.launcher3.DeviceProfile)19 PendingAnimation (com.android.launcher3.anim.PendingAnimation)19 RemoteAnimationTargetCompat (com.android.systemui.shared.system.RemoteAnimationTargetCompat)19 ItemInfo (com.android.launcher3.model.data.ItemInfo)18 DepthController (com.android.launcher3.statehandlers.DepthController)17 Task (com.android.systemui.shared.recents.model.Task)17 Rect (android.graphics.Rect)16