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

Commit 726e9ace authored by Sebastián Franco's avatar Sebastián Franco Committed by Android (Google) Code Review
Browse files

Merge "Simulating a split screen CellLayout using one CellLayout" into tm-qpr-dev

parents 3c86d903 09589326
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 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.
-->

<com.android.launcher3.MultipageCellLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:hapticFeedbackEnabled="false"
    launcher:containerType="workspace" />
 No newline at end of file
+24 −17
Original line number Diff line number Diff line
@@ -99,9 +99,9 @@ public class CellLayout extends ViewGroup {
    private Point mBorderSpace;

    @ViewDebug.ExportedProperty(category = "launcher")
    private int mCountX;
    protected int mCountX;
    @ViewDebug.ExportedProperty(category = "launcher")
    private int mCountY;
    protected int mCountY;

    private boolean mDropPending = false;

@@ -111,8 +111,8 @@ public class CellLayout extends ViewGroup {
    @Thunk final int[] mTempLocation = new int[2];
    final PointF mTmpPointF = new PointF();

    private GridOccupancy mOccupied;
    private GridOccupancy mTmpOccupied;
    protected GridOccupancy mOccupied;
    protected GridOccupancy mTmpOccupied;

    private OnTouchListener mInterceptTouchListener;

@@ -121,7 +121,7 @@ public class CellLayout extends ViewGroup {

    private static final int[] BACKGROUND_STATE_ACTIVE = new int[] { android.R.attr.state_active };
    private static final int[] BACKGROUND_STATE_DEFAULT = EMPTY_STATE_SET;
    private final Drawable mBackground;
    protected final Drawable mBackground;

    // These values allow a fixed measurement to be set on the CellLayout.
    private int mFixedWidth = -1;
@@ -154,7 +154,7 @@ public class CellLayout extends ViewGroup {
    private int mGridVisualizationRoundingRadius;
    private float mGridAlpha = 0f;
    private int mGridColor = 0;
    private float mSpringLoadedProgress = 0f;
    protected float mSpringLoadedProgress = 0f;
    private float mScrollProgress = 0f;

    // When a drag operation is in progress, holds the nearest cell to the touch point
@@ -164,7 +164,7 @@ public class CellLayout extends ViewGroup {
    private boolean mDragging = false;

    private final TimeInterpolator mEaseOutInterpolator;
    private final ShortcutAndWidgetContainer mShortcutsAndWidgets;
    protected final ShortcutAndWidgetContainer mShortcutsAndWidgets;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({WORKSPACE, HOTSEAT, FOLDER})
@@ -565,7 +565,7 @@ public class CellLayout extends ViewGroup {
        return mSpringLoadedProgress;
    }

    private void updateBgAlpha() {
    protected void updateBgAlpha() {
        mBackground.setAlpha((int) (mSpringLoadedProgress * 255));
    }

@@ -1662,7 +1662,7 @@ public class CellLayout extends ViewGroup {
     * @param spanY vertical cell span
     * @return the configuration that represents the found reorder
     */
    private ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX,
    ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX,
            int minSpanY, int spanX, int spanY) {
        ItemConfiguration solution = new ItemConfiguration();
        int[] result = new int[2];
@@ -2402,8 +2402,15 @@ public class CellLayout extends ViewGroup {
        return true;
    }

    private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
            int spanX, int spanY, int[] direction, View dragView, boolean decX,
    protected ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
            ItemConfiguration solution) {
        return findReorderSolutionRecursive(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
                direction, dragView, decX, solution);
    }

    protected ItemConfiguration findReorderSolutionRecursive(int pixelX, int pixelY, int minSpanX,
            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
            ItemConfiguration solution) {
        // Copy the current state into the solution. This solution will be manipulated as necessary.
        copyCurrentStateToSolution(solution, false);
@@ -2426,11 +2433,11 @@ public class CellLayout extends ViewGroup {
            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
            // x, then 1 in y etc.
            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
                return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY,
                        direction, dragView, false, solution);
                return findReorderSolutionRecursive(pixelX, pixelY, minSpanX, minSpanY, spanX - 1,
                        spanY, direction, dragView, false, solution);
            } else if (spanY > minSpanY) {
                return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1,
                        direction, dragView, true, solution);
                return findReorderSolutionRecursive(pixelX, pixelY, minSpanX, minSpanY, spanX,
                        spanY - 1, direction, dragView, true, solution);
            }
            solution.isSolution = false;
        } else {
@@ -2443,7 +2450,7 @@ public class CellLayout extends ViewGroup {
        return solution;
    }

    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
    protected void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
        int childCount = mShortcutsAndWidgets.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = mShortcutsAndWidgets.getChildAt(i);
@@ -2624,7 +2631,7 @@ public class CellLayout extends ViewGroup {
        return mItemPlacementDirty;
    }

    private static class ItemConfiguration extends CellAndSpan {
    static class ItemConfiguration extends CellAndSpan {
        final ArrayMap<View, CellAndSpan> map = new ArrayMap<>();
        private final ArrayMap<View, CellAndSpan> savedMap = new ArrayMap<>();
        final ArrayList<View> sortedViews = new ArrayList<>();
+7 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -138,6 +139,7 @@ import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.celllayout.CellPosMapper.TwoPanelCellPosMapper;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
@@ -730,7 +732,11 @@ public class Launcher extends StatefulActivity<LauncherState>
        }

        onDeviceProfileInitiated();
        if (FOLDABLE_SINGLE_PAGE.get() && mDeviceProfile.isTwoPanels) {
            mCellPosMapper = new TwoPanelCellPosMapper(mDeviceProfile.inv.numColumns);
        } else {
            mCellPosMapper = CellPosMapper.DEFAULT;
        }
        mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true,
                mCellPosMapper, this);
        return true;
+168 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;

import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.util.CellAndSpan;
import com.android.launcher3.util.GridOccupancy;

import java.util.function.Supplier;

/**
 * CellLayout that simulates a split in the middle for use in foldable devices.
 */
public class MultipageCellLayout extends CellLayout {

    private final Drawable mLeftBackground;
    private final Drawable mRightBackground;

    private View mSeam;

    public MultipageCellLayout(Context context) {
        this(context, null);
    }

    public MultipageCellLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MultipageCellLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mLeftBackground = getContext().getDrawable(R.drawable.bg_celllayout);
        mLeftBackground.setCallback(this);
        mLeftBackground.setAlpha(0);

        mRightBackground = getContext().getDrawable(R.drawable.bg_celllayout);
        mRightBackground.setCallback(this);
        mRightBackground.setAlpha(0);

        DeviceProfile deviceProfile = mActivity.getDeviceProfile();

        mCountX = deviceProfile.inv.numColumns * 2;
        mCountY = deviceProfile.inv.numRows;
        mSeam = new View(getContext());
        setGridSize(mCountX, mCountY);
    }

    @Override
    ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX, int minSpanY,
            int spanX, int spanY) {
        return simulateSeam(
                () -> super.closestEmptySpaceReorder(pixelX, pixelY, minSpanX, minSpanY, spanX,
                        spanY));
    }

    @Override
    protected ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
            ItemConfiguration solution) {
        return simulateSeam(
                () -> super.findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
                        direction, dragView, decX, solution));
    }

    @Override
    public ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX, int spanY,
            View dragView) {
        return simulateSeam(
                () -> super.dropInPlaceSolution(pixelX, pixelY, spanX, spanY, dragView));
    }

    protected ItemConfiguration simulateSeam(Supplier<ItemConfiguration> f) {
        CellLayoutLayoutParams lp = new CellLayoutLayoutParams(mCountX / 2, 0, 1, mCountY);
        lp.canReorder = false;
        mCountX++;
        mShortcutsAndWidgets.addViewInLayout(mSeam, lp);
        GridOccupancy auxGrid = mOccupied;
        mOccupied = createGridOccupancy();
        mTmpOccupied = new GridOccupancy(mCountX, mCountY);

        ItemConfiguration res = removeSeamFromSolution(f.get());

        mCountX--;
        mShortcutsAndWidgets.removeViewInLayout(mSeam);
        mOccupied = auxGrid;
        mTmpOccupied = new GridOccupancy(mCountX, mCountY);
        return res;
    }

    private ItemConfiguration removeSeamFromSolution(ItemConfiguration solution) {
        solution.map.forEach((view, cell) -> cell.cellX = cell.cellX > mCountX / 2
                ? cell.cellX - 1 : cell.cellX);
        solution.cellX = solution.cellX > mCountX / 2 ? solution.cellX - 1 : solution.cellX;
        return solution;
    }

    GridOccupancy createGridOccupancy() {
        GridOccupancy grid = new GridOccupancy(mCountX, mCountY);
        for (int i = 0; i < mShortcutsAndWidgets.getChildCount(); i++) {
            View view = mShortcutsAndWidgets.getChildAt(i);
            CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams();
            int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
            grid.markCells(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan, lp.cellVSpan,
                    true);
        }
        return grid;
    }

    @Override
    protected void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
        int childCount = mShortcutsAndWidgets.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = mShortcutsAndWidgets.getChildAt(i);
            CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
            int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
            CellAndSpan c = new CellAndSpan(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan,
                    lp.cellVSpan);
            solution.add(child, c);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mLeftBackground.getAlpha() > 0) {
            mLeftBackground.setState(mBackground.getState());
            mLeftBackground.draw(canvas);
        }
        if (mRightBackground.getAlpha() > 0) {
            mRightBackground.setState(mBackground.getState());
            mRightBackground.draw(canvas);
        }

        super.onDraw(canvas);
    }

    @Override
    protected void updateBgAlpha() {
        mLeftBackground.setAlpha((int) (mSpringLoadedProgress * 255));
        mRightBackground.setAlpha((int) (mSpringLoadedProgress * 255));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        Rect rect = mBackground.getBounds();
        mLeftBackground.setBounds(rect.left, rect.top, rect.right / 2 - 20, rect.bottom);
        mRightBackground.setBounds(rect.right / 2 + 20, rect.top, rect.right, rect.bottom);
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -107,6 +107,18 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
        }
    }

    /**
     * Adds view to Layout a new position and it does not trigger a layout request.
     * For more information check documentation for
     * {@code ViewGroup#addViewInLayout(View, int, LayoutParams, boolean)}
     *
     * @param child view to be added
     * @return true if the child was added, false otherwise
     */
    public boolean addViewInLayout(View child, LayoutParams layoutParams) {
        return super.addViewInLayout(child, -1, layoutParams, true);
    }

    public void setupLp(View child) {
        CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
        if (child instanceof NavigableAppWidgetHostView) {
Loading