blob: 123e8ca1e38f77fcb58d6bddcd4daf760c64945a [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
59 public void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
60 int spanY, View dragView, int[] resultDirection) {
61 createReorderAlgorithm().simulateSeam(
62 () -> {
63 super.getDirectionVectorForDrop(dragViewCenterX, dragViewCenterY, spanX, spanY,
64 dragView, resultDirection);
65 return 0;
66 });
67 }
68
69 @Override
70 public boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
71 View dragView, int[] result) {
72 return createReorderAlgorithm().simulateSeam(
73 () -> super.isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView,
74 result));
75 }
76
Sebastian Franco09589322022-11-02 15:25:58 -070077 public MultipageCellLayout(Context context, AttributeSet attrs, int defStyle) {
78 super(context, attrs, defStyle);
79 mLeftBackground = getContext().getDrawable(R.drawable.bg_celllayout);
80 mLeftBackground.setCallback(this);
81 mLeftBackground.setAlpha(0);
82
83 mRightBackground = getContext().getDrawable(R.drawable.bg_celllayout);
84 mRightBackground.setCallback(this);
85 mRightBackground.setAlpha(0);
86
87 DeviceProfile deviceProfile = mActivity.getDeviceProfile();
88
89 mCountX = deviceProfile.inv.numColumns * 2;
90 mCountY = deviceProfile.inv.numRows;
Sebastian Franco09589322022-11-02 15:25:58 -070091 setGridSize(mCountX, mCountY);
92 }
93
94 @Override
Sebastian Franco317c4fa2023-02-21 17:01:24 -080095 boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView,
96 int[] direction, boolean commit) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080097 // Add seam to x position
Sebastian Francoc515d022023-03-01 12:51:12 -080098 if (cellX >= mCountX / 2) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080099 cellX++;
100 }
101 int finalCellX = cellX;
Sebastian Franco96c46e72023-05-08 10:04:44 -0600102 return createReorderAlgorithm().simulateSeam(
Sebastian Francoee1baba2023-02-22 11:23:41 -0800103 () -> super.createAreaForResize(finalCellX, cellY, spanX, spanY, dragView,
104 direction, commit));
Sebastian Franco317c4fa2023-02-21 17:01:24 -0800105 }
106
107 @Override
Sebastian Franco96c46e72023-05-08 10:04:44 -0600108 int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
109 View dragView, int[] result, int[] resultSpan, int mode) {
110 if (pixelX >= getWidth() / 2) {
111 pixelX += getCellWidth();
112 }
113 return super.performReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, dragView,
114 result, resultSpan, mode);
115 }
116
117 @Override
118 public MulticellReorderAlgorithm createReorderAlgorithm() {
Sebastian Francoe4c03452022-12-27 14:50:02 -0600119 return new MulticellReorderAlgorithm(this);
Sebastian Franco09589322022-11-02 15:25:58 -0700120 }
121
122 @Override
Greg Kaiser484a7ea2023-11-29 20:26:47 +0000123 public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
Sebastian Franco09589322022-11-02 15:25:58 -0700124 int childCount = mShortcutsAndWidgets.getChildCount();
125 for (int i = 0; i < childCount; i++) {
126 View child = mShortcutsAndWidgets.getChildAt(i);
127 CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
128 int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
129 CellAndSpan c = new CellAndSpan(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan,
130 lp.cellVSpan);
131 solution.add(child, c);
132 }
133 }
134
135 @Override
Sebastian Franco25423862023-03-10 10:50:37 -0800136 public int getUnusedHorizontalSpace() {
137 return (int) Math.ceil(
138 (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth)
139 - ((mCountX - 1) * mBorderSpace.x)) / 2f);
140 }
141
142 @Override
Sebastian Franco09589322022-11-02 15:25:58 -0700143 protected void onDraw(Canvas canvas) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700144 float animatedWorkspaceMargin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
Sebastian Franco09589322022-11-02 15:25:58 -0700145 if (mLeftBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700146 canvas.save();
147 canvas.translate(-animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700148 mLeftBackground.setState(mBackground.getState());
149 mLeftBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700150 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700151 }
152 if (mRightBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700153 canvas.save();
154 canvas.translate(animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700155 mRightBackground.setState(mBackground.getState());
156 mRightBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700157 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700158 }
Sebastian Franco09589322022-11-02 15:25:58 -0700159 super.onDraw(canvas);
160 }
161
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700162 private void updateMarginBetweenCellLayouts() {
163 for (int i = 0; i < mShortcutsAndWidgets.getChildCount(); i++) {
164 View workspaceItem = mShortcutsAndWidgets.getChildAt(i);
165 if (!(workspaceItem instanceof Reorderable)) {
166 continue;
167 }
168 CellLayoutLayoutParams params =
169 (CellLayoutLayoutParams) workspaceItem.getLayoutParams();
170 ((Reorderable) workspaceItem).getTranslateDelegate().setTranslation(
171 MultiTranslateDelegate.INDEX_CELLAYOUT_MULTIPAGE_SPACING,
172 getMarginForGivenCellParams(params),
173 0
174 );
175
176 }
177 }
178
179 @Override
180 protected float getMarginForGivenCellParams(CellLayoutLayoutParams params) {
181 float margin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
182 return params.getCellX() >= mCountX / 2 ? margin : -margin;
183 }
184
185 @Override
186 public void setSpringLoadedProgress(float progress) {
187 super.setSpringLoadedProgress(progress);
188 updateMarginBetweenCellLayouts();
189 }
190
191 @Override
192 public void setSpaceBetweenCellLayoutsPx(int spaceBetweenCellLayoutsPx) {
193 super.setSpaceBetweenCellLayoutsPx(spaceBetweenCellLayoutsPx);
194 updateMarginBetweenCellLayouts();
195 }
196
Sebastian Franco09589322022-11-02 15:25:58 -0700197 @Override
198 protected void updateBgAlpha() {
199 mLeftBackground.setAlpha((int) (mSpringLoadedProgress * 255));
200 mRightBackground.setAlpha((int) (mSpringLoadedProgress * 255));
201 }
202
203 @Override
204 protected void onLayout(boolean changed, int l, int t, int r, int b) {
205 super.onLayout(changed, l, t, r, b);
206 Rect rect = mBackground.getBounds();
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700207 int middlePointInPixels = rect.centerX();
208 mLeftBackground.setBounds(rect.left, rect.top, middlePointInPixels, rect.bottom);
209 mRightBackground.setBounds(middlePointInPixels, rect.top, rect.right, rect.bottom);
Sebastian Franco09589322022-11-02 15:25:58 -0700210 }
Sebastian Francoe4c03452022-12-27 14:50:02 -0600211
212 public void setCountX(int countX) {
213 mCountX = countX;
214 }
215
216 public void setCountY(int countY) {
217 mCountY = countY;
218 }
219
220 public void setOccupied(GridOccupancy occupied) {
221 mOccupied = occupied;
222 }
223
224 public boolean isSeamWasAdded() {
225 return mSeamWasAdded;
226 }
227
228 public void setSeamWasAdded(boolean seamWasAdded) {
229 mSeamWasAdded = seamWasAdded;
230 }
Sebastian Franco09589322022-11-02 15:25:58 -0700231}