blob: 0ec9034cc7415f914cc932205e5098c3e806b031 [file] [log] [blame]
Sebastian Franco09589322022-11-02 15:25:58 -07001/*
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 */
16package com.android.launcher3;
17
18import android.content.Context;
19import android.graphics.Canvas;
20import android.graphics.Rect;
21import android.graphics.drawable.Drawable;
22import android.util.AttributeSet;
23import android.view.View;
24
25import com.android.launcher3.celllayout.CellLayoutLayoutParams;
Sebastian Franco5f0af4f2023-11-21 10:45:45 -060026import com.android.launcher3.celllayout.ItemConfiguration;
Sebastian Francoe4c03452022-12-27 14:50:02 -060027import com.android.launcher3.celllayout.MulticellReorderAlgorithm;
Sebastian Franco09589322022-11-02 15:25:58 -070028import com.android.launcher3.util.CellAndSpan;
29import com.android.launcher3.util.GridOccupancy;
Sebastian Franco9ea36d42023-09-21 13:56:42 -070030import com.android.launcher3.util.MultiTranslateDelegate;
Sebastian Franco09589322022-11-02 15:25:58 -070031
Sebastian Franco09589322022-11-02 15:25:58 -070032/**
33 * CellLayout that simulates a split in the middle for use in foldable devices.
34 */
35public class MultipageCellLayout extends CellLayout {
36
37 private final Drawable mLeftBackground;
38 private final Drawable mRightBackground;
39
Sebastian Franco317c4fa2023-02-21 17:01:24 -080040 private boolean mSeamWasAdded = false;
41
Sebastian Franco09589322022-11-02 15:25:58 -070042 public MultipageCellLayout(Context context) {
43 this(context, null);
44 }
45
46 public MultipageCellLayout(Context context, AttributeSet attrs) {
47 this(context, attrs, 0);
48 }
49
Sebastian Franco96c46e72023-05-08 10:04:44 -060050 @Override
51 protected int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY,
52 int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
53 return createReorderAlgorithm().simulateSeam(
54 () -> super.findNearestArea(relativeXPos, relativeYPos, minSpanX, minSpanY, spanX,
55 spanY, ignoreOccupied, result, resultSpan));
56 }
57
58 @Override
Sebastian Franco96c46e72023-05-08 10:04:44 -060059 public boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
60 View dragView, int[] result) {
61 return createReorderAlgorithm().simulateSeam(
62 () -> super.isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView,
63 result));
64 }
65
Sebastian Franco09589322022-11-02 15:25:58 -070066 public MultipageCellLayout(Context context, AttributeSet attrs, int defStyle) {
67 super(context, attrs, defStyle);
68 mLeftBackground = getContext().getDrawable(R.drawable.bg_celllayout);
69 mLeftBackground.setCallback(this);
70 mLeftBackground.setAlpha(0);
71
72 mRightBackground = getContext().getDrawable(R.drawable.bg_celllayout);
73 mRightBackground.setCallback(this);
74 mRightBackground.setAlpha(0);
75
76 DeviceProfile deviceProfile = mActivity.getDeviceProfile();
77
78 mCountX = deviceProfile.inv.numColumns * 2;
79 mCountY = deviceProfile.inv.numRows;
Sebastian Franco09589322022-11-02 15:25:58 -070080 setGridSize(mCountX, mCountY);
81 }
82
83 @Override
Sebastian Franco317c4fa2023-02-21 17:01:24 -080084 boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView,
85 int[] direction, boolean commit) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080086 // Add seam to x position
Sebastian Francoc515d022023-03-01 12:51:12 -080087 if (cellX >= mCountX / 2) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080088 cellX++;
89 }
90 int finalCellX = cellX;
Sebastian Franco96c46e72023-05-08 10:04:44 -060091 return createReorderAlgorithm().simulateSeam(
Sebastian Francoee1baba2023-02-22 11:23:41 -080092 () -> super.createAreaForResize(finalCellX, cellY, spanX, spanY, dragView,
93 direction, commit));
Sebastian Franco317c4fa2023-02-21 17:01:24 -080094 }
95
96 @Override
Sebastian Franco96c46e72023-05-08 10:04:44 -060097 int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
98 View dragView, int[] result, int[] resultSpan, int mode) {
99 if (pixelX >= getWidth() / 2) {
100 pixelX += getCellWidth();
101 }
102 return super.performReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, dragView,
103 result, resultSpan, mode);
104 }
105
106 @Override
107 public MulticellReorderAlgorithm createReorderAlgorithm() {
Sebastian Francoe4c03452022-12-27 14:50:02 -0600108 return new MulticellReorderAlgorithm(this);
Sebastian Franco09589322022-11-02 15:25:58 -0700109 }
110
111 @Override
Sebastián Franco61fbd182023-11-29 21:30:43 +0000112 public void copyCurrentStateToSolution(ItemConfiguration solution) {
Sebastian Franco09589322022-11-02 15:25:58 -0700113 int childCount = mShortcutsAndWidgets.getChildCount();
114 for (int i = 0; i < childCount; i++) {
115 View child = mShortcutsAndWidgets.getChildAt(i);
116 CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
117 int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
118 CellAndSpan c = new CellAndSpan(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan,
119 lp.cellVSpan);
120 solution.add(child, c);
121 }
122 }
123
124 @Override
Sebastian Franco25423862023-03-10 10:50:37 -0800125 public int getUnusedHorizontalSpace() {
126 return (int) Math.ceil(
127 (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth)
128 - ((mCountX - 1) * mBorderSpace.x)) / 2f);
129 }
130
131 @Override
Sebastian Franco09589322022-11-02 15:25:58 -0700132 protected void onDraw(Canvas canvas) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700133 float animatedWorkspaceMargin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
Sebastian Franco09589322022-11-02 15:25:58 -0700134 if (mLeftBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700135 canvas.save();
136 canvas.translate(-animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700137 mLeftBackground.setState(mBackground.getState());
138 mLeftBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700139 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700140 }
141 if (mRightBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700142 canvas.save();
143 canvas.translate(animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700144 mRightBackground.setState(mBackground.getState());
145 mRightBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700146 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700147 }
Sebastian Franco09589322022-11-02 15:25:58 -0700148 super.onDraw(canvas);
149 }
150
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700151 private void updateMarginBetweenCellLayouts() {
152 for (int i = 0; i < mShortcutsAndWidgets.getChildCount(); i++) {
153 View workspaceItem = mShortcutsAndWidgets.getChildAt(i);
154 if (!(workspaceItem instanceof Reorderable)) {
155 continue;
156 }
157 CellLayoutLayoutParams params =
158 (CellLayoutLayoutParams) workspaceItem.getLayoutParams();
159 ((Reorderable) workspaceItem).getTranslateDelegate().setTranslation(
160 MultiTranslateDelegate.INDEX_CELLAYOUT_MULTIPAGE_SPACING,
161 getMarginForGivenCellParams(params),
162 0
163 );
164
165 }
166 }
167
168 @Override
169 protected float getMarginForGivenCellParams(CellLayoutLayoutParams params) {
170 float margin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
171 return params.getCellX() >= mCountX / 2 ? margin : -margin;
172 }
173
174 @Override
175 public void setSpringLoadedProgress(float progress) {
176 super.setSpringLoadedProgress(progress);
177 updateMarginBetweenCellLayouts();
178 }
179
180 @Override
181 public void setSpaceBetweenCellLayoutsPx(int spaceBetweenCellLayoutsPx) {
182 super.setSpaceBetweenCellLayoutsPx(spaceBetweenCellLayoutsPx);
183 updateMarginBetweenCellLayouts();
184 }
185
Sebastian Franco09589322022-11-02 15:25:58 -0700186 @Override
187 protected void updateBgAlpha() {
188 mLeftBackground.setAlpha((int) (mSpringLoadedProgress * 255));
189 mRightBackground.setAlpha((int) (mSpringLoadedProgress * 255));
190 }
191
192 @Override
193 protected void onLayout(boolean changed, int l, int t, int r, int b) {
194 super.onLayout(changed, l, t, r, b);
195 Rect rect = mBackground.getBounds();
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700196 int middlePointInPixels = rect.centerX();
197 mLeftBackground.setBounds(rect.left, rect.top, middlePointInPixels, rect.bottom);
198 mRightBackground.setBounds(middlePointInPixels, rect.top, rect.right, rect.bottom);
Sebastian Franco09589322022-11-02 15:25:58 -0700199 }
Sebastian Francoe4c03452022-12-27 14:50:02 -0600200
201 public void setCountX(int countX) {
202 mCountX = countX;
203 }
204
205 public void setCountY(int countY) {
206 mCountY = countY;
207 }
208
209 public void setOccupied(GridOccupancy occupied) {
210 mOccupied = occupied;
211 }
212
213 public boolean isSeamWasAdded() {
214 return mSeamWasAdded;
215 }
216
217 public void setSeamWasAdded(boolean seamWasAdded) {
218 mSeamWasAdded = seamWasAdded;
219 }
Sebastian Franco09589322022-11-02 15:25:58 -0700220}