blob: 4b5c9ef8e48c78d9a5f3c174d1f74c0755f936c0 [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 Francoe4c03452022-12-27 14:50:02 -060026import com.android.launcher3.celllayout.MulticellReorderAlgorithm;
Sebastian Franco09589322022-11-02 15:25:58 -070027import com.android.launcher3.util.CellAndSpan;
28import com.android.launcher3.util.GridOccupancy;
Sebastian Franco9ea36d42023-09-21 13:56:42 -070029import com.android.launcher3.util.MultiTranslateDelegate;
Sebastian Franco09589322022-11-02 15:25:58 -070030
Sebastian Franco09589322022-11-02 15:25:58 -070031/**
32 * CellLayout that simulates a split in the middle for use in foldable devices.
33 */
34public class MultipageCellLayout extends CellLayout {
35
36 private final Drawable mLeftBackground;
37 private final Drawable mRightBackground;
38
Sebastian Franco317c4fa2023-02-21 17:01:24 -080039 private boolean mSeamWasAdded = false;
40
Sebastian Franco09589322022-11-02 15:25:58 -070041 public MultipageCellLayout(Context context) {
42 this(context, null);
43 }
44
45 public MultipageCellLayout(Context context, AttributeSet attrs) {
46 this(context, attrs, 0);
47 }
48
Sebastian Franco96c46e72023-05-08 10:04:44 -060049 @Override
50 protected int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY,
51 int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
52 return createReorderAlgorithm().simulateSeam(
53 () -> super.findNearestArea(relativeXPos, relativeYPos, minSpanX, minSpanY, spanX,
54 spanY, ignoreOccupied, result, resultSpan));
55 }
56
57 @Override
58 public void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
59 int spanY, View dragView, int[] resultDirection) {
60 createReorderAlgorithm().simulateSeam(
61 () -> {
62 super.getDirectionVectorForDrop(dragViewCenterX, dragViewCenterY, spanX, spanY,
63 dragView, resultDirection);
64 return 0;
65 });
66 }
67
68 @Override
69 public boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
70 View dragView, int[] result) {
71 return createReorderAlgorithm().simulateSeam(
72 () -> super.isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView,
73 result));
74 }
75
Sebastian Franco09589322022-11-02 15:25:58 -070076 public MultipageCellLayout(Context context, AttributeSet attrs, int defStyle) {
77 super(context, attrs, defStyle);
78 mLeftBackground = getContext().getDrawable(R.drawable.bg_celllayout);
79 mLeftBackground.setCallback(this);
80 mLeftBackground.setAlpha(0);
81
82 mRightBackground = getContext().getDrawable(R.drawable.bg_celllayout);
83 mRightBackground.setCallback(this);
84 mRightBackground.setAlpha(0);
85
86 DeviceProfile deviceProfile = mActivity.getDeviceProfile();
87
88 mCountX = deviceProfile.inv.numColumns * 2;
89 mCountY = deviceProfile.inv.numRows;
Sebastian Franco09589322022-11-02 15:25:58 -070090 setGridSize(mCountX, mCountY);
91 }
92
93 @Override
Sebastian Franco317c4fa2023-02-21 17:01:24 -080094 boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, View dragView,
95 int[] direction, boolean commit) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080096 // Add seam to x position
Sebastian Francoc515d022023-03-01 12:51:12 -080097 if (cellX >= mCountX / 2) {
Sebastian Francoee1baba2023-02-22 11:23:41 -080098 cellX++;
99 }
100 int finalCellX = cellX;
Sebastian Franco96c46e72023-05-08 10:04:44 -0600101 return createReorderAlgorithm().simulateSeam(
Sebastian Francoee1baba2023-02-22 11:23:41 -0800102 () -> super.createAreaForResize(finalCellX, cellY, spanX, spanY, dragView,
103 direction, commit));
Sebastian Franco317c4fa2023-02-21 17:01:24 -0800104 }
105
106 @Override
Sebastian Franco96c46e72023-05-08 10:04:44 -0600107 int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
108 View dragView, int[] result, int[] resultSpan, int mode) {
109 if (pixelX >= getWidth() / 2) {
110 pixelX += getCellWidth();
111 }
112 return super.performReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, dragView,
113 result, resultSpan, mode);
114 }
115
116 @Override
117 public MulticellReorderAlgorithm createReorderAlgorithm() {
Sebastian Francoe4c03452022-12-27 14:50:02 -0600118 return new MulticellReorderAlgorithm(this);
Sebastian Franco09589322022-11-02 15:25:58 -0700119 }
120
121 @Override
Sebastian Francoe4c03452022-12-27 14:50:02 -0600122 public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
Sebastian Franco09589322022-11-02 15:25:58 -0700123 int childCount = mShortcutsAndWidgets.getChildCount();
124 for (int i = 0; i < childCount; i++) {
125 View child = mShortcutsAndWidgets.getChildAt(i);
126 CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
127 int seamOffset = lp.getCellX() >= mCountX / 2 && lp.canReorder ? 1 : 0;
128 CellAndSpan c = new CellAndSpan(lp.getCellX() + seamOffset, lp.getCellY(), lp.cellHSpan,
129 lp.cellVSpan);
130 solution.add(child, c);
131 }
132 }
133
134 @Override
Sebastian Franco25423862023-03-10 10:50:37 -0800135 public int getUnusedHorizontalSpace() {
136 return (int) Math.ceil(
137 (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - (mCountX * mCellWidth)
138 - ((mCountX - 1) * mBorderSpace.x)) / 2f);
139 }
140
141 @Override
Sebastian Franco09589322022-11-02 15:25:58 -0700142 protected void onDraw(Canvas canvas) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700143 float animatedWorkspaceMargin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
Sebastian Franco09589322022-11-02 15:25:58 -0700144 if (mLeftBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700145 canvas.save();
146 canvas.translate(-animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700147 mLeftBackground.setState(mBackground.getState());
148 mLeftBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700149 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700150 }
151 if (mRightBackground.getAlpha() > 0) {
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700152 canvas.save();
153 canvas.translate(animatedWorkspaceMargin, 0);
Sebastian Franco09589322022-11-02 15:25:58 -0700154 mRightBackground.setState(mBackground.getState());
155 mRightBackground.draw(canvas);
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700156 canvas.restore();
Sebastian Franco09589322022-11-02 15:25:58 -0700157 }
Sebastian Franco09589322022-11-02 15:25:58 -0700158 super.onDraw(canvas);
159 }
160
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700161 private void updateMarginBetweenCellLayouts() {
162 for (int i = 0; i < mShortcutsAndWidgets.getChildCount(); i++) {
163 View workspaceItem = mShortcutsAndWidgets.getChildAt(i);
164 if (!(workspaceItem instanceof Reorderable)) {
165 continue;
166 }
167 CellLayoutLayoutParams params =
168 (CellLayoutLayoutParams) workspaceItem.getLayoutParams();
169 ((Reorderable) workspaceItem).getTranslateDelegate().setTranslation(
170 MultiTranslateDelegate.INDEX_CELLAYOUT_MULTIPAGE_SPACING,
171 getMarginForGivenCellParams(params),
172 0
173 );
174
175 }
176 }
177
178 @Override
179 protected float getMarginForGivenCellParams(CellLayoutLayoutParams params) {
180 float margin = mSpaceBetweenCellLayoutsPx * mSpringLoadedProgress;
181 return params.getCellX() >= mCountX / 2 ? margin : -margin;
182 }
183
184 @Override
185 public void setSpringLoadedProgress(float progress) {
186 super.setSpringLoadedProgress(progress);
187 updateMarginBetweenCellLayouts();
188 }
189
190 @Override
191 public void setSpaceBetweenCellLayoutsPx(int spaceBetweenCellLayoutsPx) {
192 super.setSpaceBetweenCellLayoutsPx(spaceBetweenCellLayoutsPx);
193 updateMarginBetweenCellLayouts();
194 }
195
Sebastian Franco09589322022-11-02 15:25:58 -0700196 @Override
197 protected void updateBgAlpha() {
198 mLeftBackground.setAlpha((int) (mSpringLoadedProgress * 255));
199 mRightBackground.setAlpha((int) (mSpringLoadedProgress * 255));
200 }
201
202 @Override
203 protected void onLayout(boolean changed, int l, int t, int r, int b) {
204 super.onLayout(changed, l, t, r, b);
205 Rect rect = mBackground.getBounds();
Sebastian Franco9ea36d42023-09-21 13:56:42 -0700206 int middlePointInPixels = rect.centerX();
207 mLeftBackground.setBounds(rect.left, rect.top, middlePointInPixels, rect.bottom);
208 mRightBackground.setBounds(middlePointInPixels, rect.top, rect.right, rect.bottom);
Sebastian Franco09589322022-11-02 15:25:58 -0700209 }
Sebastian Francoe4c03452022-12-27 14:50:02 -0600210
211 public void setCountX(int countX) {
212 mCountX = countX;
213 }
214
215 public void setCountY(int countY) {
216 mCountY = countY;
217 }
218
219 public void setOccupied(GridOccupancy occupied) {
220 mOccupied = occupied;
221 }
222
223 public boolean isSeamWasAdded() {
224 return mSeamWasAdded;
225 }
226
227 public void setSeamWasAdded(boolean seamWasAdded) {
228 mSeamWasAdded = seamWasAdded;
229 }
Sebastian Franco09589322022-11-02 15:25:58 -0700230}