Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bbebe24 authored by Steven Ng's avatar Steven Ng Committed by Android (Google) Code Review
Browse files

Merge "Add an animation for invalid widget resizing in 2 panel UI" into sc-v2-dev

parents e4057e62 4b346108
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
    <dimen name="widget_handle_margin">13dp</dimen>
    <dimen name="resize_frame_background_padding">24dp</dimen>
    <dimen name="resize_frame_margin">22dp</dimen>
    <dimen name="resize_frame_invalid_drag_across_two_panel_opacity_margin">24dp</dimen>

    <!-- App widget reconfigure button -->
    <dimen name="widget_reconfigure_button_corner_radius">14dp</dimen>
+113 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ package com.android.launcher3;

import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;

import static com.android.launcher3.CellLayout.SPRING_LOADED_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_COMPLETED;
@@ -9,6 +10,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -29,6 +32,7 @@ import androidx.annotation.Px;

import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
@@ -49,12 +53,14 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
    private static final String KEY_RECONFIGURABLE_WIDGET_EDUCATION_TIP_SEEN =
            "launcher.reconfigurable_widget_education_tip_seen";
    private static final Rect sTmpRect = new Rect();
    private static final Rect sTmpRect2 = new Rect();

    private static final int HANDLE_COUNT = 4;
    private static final int INDEX_LEFT = 0;
    private static final int INDEX_TOP = 1;
    private static final int INDEX_RIGHT = 2;
    private static final int INDEX_BOTTOM = 3;
    private static final float MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE = 0.5f;

    private final Launcher mLauncher;
    private final DragViewStateAnnouncer mStateAnnouncer;
@@ -103,6 +109,16 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O

    private final InstanceId logInstanceId = new InstanceIdSequence().newInstanceId();

    private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;

    /**
     * In the two panel UI, it is not possible to resize a widget to cross its host
     * {@link CellLayout}'s sibling. When this happens, we gradually reduce the opacity of the
     * sibling {@link CellLayout} from 1f to
     * {@link #MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE}.
     */
    private final float mDragAcrossTwoPanelOpacityMargin;

    private boolean mLeftBorderActive;
    private boolean mRightBorderActive;
    private boolean mTopBorderActive;
@@ -149,6 +165,10 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
        for (int i = 0; i < HANDLE_COUNT; i++) {
            mSystemGestureExclusionRects.add(new Rect());
        }

        mDragAcrossTwoPanelOpacityMargin = mLauncher.getResources().getDimensionPixelSize(
                R.dimen.resize_frame_invalid_drag_across_two_panel_opacity_margin);
        mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
    }

    @Override
@@ -359,6 +379,37 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
            lp.y = sTmpRect.top;
        }

        // Handle invalid resize across CellLayouts in the two panel UI.
        if (mCellLayout.getParent() instanceof Workspace) {
            Workspace workspace = (Workspace) mCellLayout.getParent();
            CellLayout pairedCellLayout = workspace.getScreenPair(mCellLayout);
            if (pairedCellLayout != null) {
                Rect focusedCellLayoutBound = sTmpRect;
                mDragLayerRelativeCoordinateHelper.viewToRect(mCellLayout, focusedCellLayoutBound);
                Rect resizeFrameBound = sTmpRect2;
                findViewById(R.id.widget_resize_frame).getGlobalVisibleRect(resizeFrameBound);
                float progress = 1f;
                if (workspace.indexOfChild(pairedCellLayout) < workspace.indexOfChild(mCellLayout)
                        && mDeltaX < 0
                        && resizeFrameBound.left < focusedCellLayoutBound.left) {
                    // Resize from right to left.
                    progress = (mDragAcrossTwoPanelOpacityMargin + mDeltaX)
                            / mDragAcrossTwoPanelOpacityMargin;
                } else if (workspace.indexOfChild(pairedCellLayout)
                                > workspace.indexOfChild(mCellLayout)
                        && mDeltaX > 0
                        && resizeFrameBound.right > focusedCellLayoutBound.right) {
                    // Resize from left to right.
                    progress = (mDragAcrossTwoPanelOpacityMargin - mDeltaX)
                            / mDragAcrossTwoPanelOpacityMargin;
                }
                float alpha = Math.max(MIN_OPACITY_FOR_CELL_LAYOUT_DURING_INVALID_RESIZE, progress);
                float springLoadedProgress = Math.min(1f, 1f - progress);
                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, alpha,
                        springLoadedProgress);
            }
        }

        requestLayout();
    }

@@ -515,13 +566,24 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
        }

        final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
        final CellLayout pairedCellLayout;
        if (mCellLayout.getParent() instanceof Workspace) {
            Workspace workspace = (Workspace) mCellLayout.getParent();
            pairedCellLayout = workspace.getScreenPair(mCellLayout);
        } else {
            pairedCellLayout = null;
        }
        if (!animate) {
            lp.width = newWidth;
            lp.height = newHeight;
            lp.x = newX;
            lp.y = newY;
            for (int i = 0; i < HANDLE_COUNT; i++) {
                mDragHandles[i].setAlpha(1.0f);
                mDragHandles[i].setAlpha(1f);
            }
            if (pairedCellLayout != null) {
                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
                        /* springLoadedProgress= */ 0f);
            }
            requestLayout();
        } else {
@@ -538,6 +600,10 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
                set.play(mFirstFrameAnimatorHelper.addTo(
                        ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
            }
            if (pairedCellLayout != null) {
                updateInvalidResizeEffect(mCellLayout, pairedCellLayout, /* alpha= */ 1f,
                        /* springLoadedProgress= */ 0f, /* animatorSet= */ set);
            }
            set.setDuration(SNAP_DURATION);
            set.start();
        }
@@ -624,6 +690,52 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
        }
    }

    private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
            float alpha, float springLoadedProgress) {
        updateInvalidResizeEffect(cellLayout, pairedCellLayout, alpha,
                springLoadedProgress, /* animatorSet= */ null);
    }

    private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,
            float alpha, float springLoadedProgress, @Nullable AnimatorSet animatorSet) {
        int childCount = pairedCellLayout.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = pairedCellLayout.getChildAt(i);
            if (animatorSet != null) {
                animatorSet.play(
                        mFirstFrameAnimatorHelper.addTo(
                                ObjectAnimator.ofFloat(child, ALPHA, alpha)));
            } else {
                child.setAlpha(alpha);
            }
        }
        if (animatorSet != null) {
            animatorSet.play(mFirstFrameAnimatorHelper.addTo(
                    ObjectAnimator.ofFloat(cellLayout, SPRING_LOADED_PROGRESS,
                            springLoadedProgress)));
            animatorSet.play(mFirstFrameAnimatorHelper.addTo(
                    ObjectAnimator.ofFloat(pairedCellLayout, SPRING_LOADED_PROGRESS,
                            springLoadedProgress)));
        } else {
            cellLayout.setSpringLoadedProgress(springLoadedProgress);
            pairedCellLayout.setSpringLoadedProgress(springLoadedProgress);
        }

        boolean shouldShowCellLayoutBorder = springLoadedProgress > 0f;
        if (animatorSet != null) {
            animatorSet.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animator) {
                    cellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
                    pairedCellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
                }
            });
        } else {
            cellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
            pairedCellLayout.setIsDragOverlapping(shouldShowCellLayoutBorder);
        }
    }

    @Override
    protected boolean isOfType(int type) {
        return (type & TYPE_WIDGET_RESIZE_FRAME) != 0;
+2 −2
Original line number Diff line number Diff line
@@ -2128,7 +2128,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
            actualIds.add(id);
        }
        int firstId = visibleIds.getArray().get(0);
        int pairId = mWorkspace.getPagePair(firstId);
        int pairId = mWorkspace.getScreenPair(firstId);
        // Double check that actual screenIds contains the visibleId, as empty screens are hidden
        // in single panel.
        if (actualIds.contains(firstId)) {
@@ -2212,7 +2212,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
            // Some empty pages might have been removed while the phone was in a single panel
            // mode, so we want to add those empty pages back.
            IntSet screenIds = IntSet.wrap(orderedScreenIds);
            orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getPagePair(screenId)));
            orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
            orderedScreenIds = screenIds.getArray();
        }

+24 −7
Original line number Diff line number Diff line
@@ -651,7 +651,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>

            // If the icon was dragged from Hotseat, there is no page pair
            if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
                int pagePairScreenId = getPagePair(dragObject.dragInfo.screenId);
                int pagePairScreenId = getScreenPair(dragObject.dragInfo.screenId);
                CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
                if (pagePair == null) {
                    // TODO: after http://b/198820019 is fixed, remove this
@@ -917,16 +917,33 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
    }

    /**
     * Returns the page that is shown together with the given page when two panel is enabled.
     * Returns the screen ID of a page that is shown together with the given page screen ID when the
     * two panel UI is enabled.
     */
    public int getPagePair(int page) {
        if (page % 2 == 0) {
            return page + 1;
    public int getScreenPair(int screenId) {
        if (screenId % 2 == 0) {
            return screenId + 1;
        } else {
            return page - 1;
            return screenId - 1;
        }
    }

    /**
     * Returns {@link CellLayout} that is shown together with the given {@link CellLayout} when the
     * two panel UI is enabled.
     */
    @Nullable
    public CellLayout getScreenPair(CellLayout cellLayout) {
        if (!isTwoPanelEnabled()) {
            return null;
        }
        int screenId = getIdForScreen(cellLayout);
        if (screenId == -1) {
            return null;
        }
        return getScreenWithId(getScreenPair(screenId));
    }

    public void stripEmptyScreens() {
        if (mLauncher.isWorkspaceLoading()) {
            // Don't strip empty screens if the workspace is still loading.
@@ -959,7 +976,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
            Iterator<Integer> removeScreensIterator = removeScreens.iterator();
            while (removeScreensIterator.hasNext()) {
                int pageToRemove = removeScreensIterator.next();
                int pagePair = getPagePair(pageToRemove);
                int pagePair = getScreenPair(pageToRemove);
                if (!removeScreens.contains(pagePair)) {
                    // The page pair isn't empty so we want to remove the current page from the
                    // removable pages' collection