• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3;
17 
18 import android.content.Context;
19 import android.graphics.Canvas;
20 import android.graphics.Rect;
21 import android.graphics.drawable.Drawable;
22 import android.util.AttributeSet;
23 import android.view.View;
24 
25 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
26 import com.android.launcher3.celllayout.MulticellReorderAlgorithm;
27 import com.android.launcher3.util.CellAndSpan;
28 import com.android.launcher3.util.GridOccupancy;
29 
30 /**
31  * CellLayout that simulates a split in the middle for use in foldable devices.
32  */
33 public class MultipageCellLayout extends CellLayout {
34 
35     private final Drawable mLeftBackground;
36     private final Drawable mRightBackground;
37 
38     private boolean mSeamWasAdded = false;
39 
MultipageCellLayout(Context context)40     public MultipageCellLayout(Context context) {
41         this(context, null);
42     }
43 
MultipageCellLayout(Context context, AttributeSet attrs)44     public MultipageCellLayout(Context context, AttributeSet attrs) {
45         this(context, attrs, 0);
46     }
47 
48     @Override
findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY, int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan)49     protected int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY,
50             int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
51         return createReorderAlgorithm().simulateSeam(
52                 () -> super.findNearestArea(relativeXPos, relativeYPos, minSpanX, minSpanY, spanX,
53                         spanY, ignoreOccupied, result, resultSpan));
54     }
55 
56     @Override
getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, int spanY, View dragView, int[] resultDirection)57     public void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
58             int spanY, View dragView, int[] resultDirection) {
59         createReorderAlgorithm().simulateSeam(
60                 () -> {
61                     super.getDirectionVectorForDrop(dragViewCenterX, dragViewCenterY, spanX, spanY,
62                             dragView, resultDirection);
63                     return 0;
64                 });
65     }
66 
67     @Override
isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, View dragView, int[] result)68     public boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
69             View dragView, int[] result) {
70         return createReorderAlgorithm().simulateSeam(
71                 () -> super.isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView,
72                         result));
73     }
74 
MultipageCellLayout(Context context, AttributeSet attrs, int defStyle)75     public MultipageCellLayout(Context context, AttributeSet attrs, int defStyle) {
76         super(context, attrs, defStyle);
77         mLeftBackground = getContext().getDrawable(R.drawable.bg_celllayout);
78         mLeftBackground.setCallback(this);
79         mLeftBackground.setAlpha(0);
80 
81         mRightBackground = getContext().getDrawable(R.drawable.bg_celllayout);
82         mRightBackground.setCallback(this);
83         mRightBackground.setAlpha(0);
84 
85         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
86 
87         mCountX = deviceProfile.inv.numColumns * 2;
88         mCountY = deviceProfile.inv.numRows;
89         setGridSize(mCountX, mCountY);
90     }
91 
92     @Override
createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView, int[] direction, boolean commit)93     boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView,
94             int[] direction, boolean commit) {
95         // Add seam to x position
96         if (cellX >= mCountX / 2) {
97             cellX++;
98         }
99         int finalCellX = cellX;
100         return createReorderAlgorithm().simulateSeam(
101                 () -> super.createAreaForResize(finalCellX, cellY, spanX, spanY, dragView,
102                         direction, commit));
103     }
104 
105     @Override
performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, View dragView, int[] result, int[] resultSpan, int mode)106     int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
107             View dragView, int[] result, int[] resultSpan, int mode) {
108         if (pixelX >= getWidth() / 2) {
109             pixelX += getCellWidth();
110         }
111         return super.performReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, dragView,
112                 result, resultSpan, mode);
113     }
114 
115     @Override
createReorderAlgorithm()116     public MulticellReorderAlgorithm createReorderAlgorithm() {
117         return new MulticellReorderAlgorithm(this);
118     }
119 
120     @Override
copyCurrentStateToSolution(ItemConfiguration solution, boolean temp)121     public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
122         int childCount = mShortcutsAndWidgets.getChildCount();
123         for (int i = 0; i < childCount; i++) {
124             View child = mShortcutsAndWidgets.getChildAt(i);
125             CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
126             int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
127             CellAndSpan c = new CellAndSpan(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan,
128                     lp.cellVSpan);
129             solution.add(child, c);
130         }
131     }
132 
133     @Override
getUnusedHorizontalSpace()134     public int getUnusedHorizontalSpace() {
135         return (int) Math.ceil(
136                 (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth)
137                         - ((mCountX - 1) * mBorderSpace.x)) / 2f);
138     }
139 
140     @Override
onDraw(Canvas canvas)141     protected void onDraw(Canvas canvas) {
142         if (mLeftBackground.getAlpha() > 0) {
143             mLeftBackground.setState(mBackground.getState());
144             mLeftBackground.draw(canvas);
145         }
146         if (mRightBackground.getAlpha() > 0) {
147             mRightBackground.setState(mBackground.getState());
148             mRightBackground.draw(canvas);
149         }
150 
151         super.onDraw(canvas);
152     }
153 
154     @Override
updateBgAlpha()155     protected void updateBgAlpha() {
156         mLeftBackground.setAlpha((int) (mSpringLoadedProgress * 255));
157         mRightBackground.setAlpha((int) (mSpringLoadedProgress * 255));
158     }
159 
160     @Override
onLayout(boolean changed, int l, int t, int r, int b)161     protected void onLayout(boolean changed, int l, int t, int r, int b) {
162         super.onLayout(changed, l, t, r, b);
163         Rect rect = mBackground.getBounds();
164         mLeftBackground.setBounds(rect.left, rect.top, rect.right / 2 - 20, rect.bottom);
165         mRightBackground.setBounds(rect.right / 2 + 20, rect.top, rect.right, rect.bottom);
166     }
167 
setCountX(int countX)168     public void setCountX(int countX) {
169         mCountX = countX;
170     }
171 
setCountY(int countY)172     public void setCountY(int countY) {
173         mCountY = countY;
174     }
175 
setOccupied(GridOccupancy occupied)176     public void setOccupied(GridOccupancy occupied) {
177         mOccupied = occupied;
178     }
179 
isSeamWasAdded()180     public boolean isSeamWasAdded() {
181         return mSeamWasAdded;
182     }
183 
setSeamWasAdded(boolean seamWasAdded)184     public void setSeamWasAdded(boolean seamWasAdded) {
185         mSeamWasAdded = seamWasAdded;
186     }
187 }
188