• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.launcher3;
18 
19 import static android.view.MotionEvent.ACTION_DOWN;
20 
21 import static com.android.launcher3.CellLayout.FOLDER;
22 import static com.android.launcher3.CellLayout.HOTSEAT;
23 import static com.android.launcher3.CellLayout.WORKSPACE;
24 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_WIDGET_CENTERING;
25 
26 import android.app.WallpaperManager;
27 import android.content.Context;
28 import android.graphics.Point;
29 import android.graphics.PointF;
30 import android.graphics.Rect;
31 import android.view.MotionEvent;
32 import android.view.View;
33 import android.view.ViewGroup;
34 
35 import com.android.launcher3.CellLayout.ContainerType;
36 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
37 import com.android.launcher3.folder.FolderIcon;
38 import com.android.launcher3.model.data.ItemInfo;
39 import com.android.launcher3.views.ActivityContext;
40 import com.android.launcher3.widget.NavigableAppWidgetHostView;
41 
42 public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.FolderIconParent {
43     static final String TAG = "ShortcutAndWidgetContainer";
44 
45     // These are temporary variables to prevent having to allocate a new object just to
46     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
47     private final int[] mTmpCellXY = new int[2];
48 
49     private final Rect mTempRect = new Rect();
50 
51     @ContainerType
52     private final int mContainerType;
53     private final WallpaperManager mWallpaperManager;
54 
55     private int mCellWidth;
56     private int mCellHeight;
57     private Point mBorderSpace;
58 
59     private int mCountX;
60     private int mCountY;
61 
62     private final ActivityContext mActivity;
63     private boolean mInvertIfRtl = false;
64 
ShortcutAndWidgetContainer(Context context, @ContainerType int containerType)65     public ShortcutAndWidgetContainer(Context context, @ContainerType int containerType) {
66         super(context);
67         mActivity = ActivityContext.lookupContext(context);
68         mWallpaperManager = WallpaperManager.getInstance(context);
69         mContainerType = containerType;
70     }
71 
setCellDimensions(int cellWidth, int cellHeight, int countX, int countY, Point borderSpace)72     public void setCellDimensions(int cellWidth, int cellHeight, int countX, int countY,
73             Point borderSpace) {
74         mCellWidth = cellWidth;
75         mCellHeight = cellHeight;
76         mCountX = countX;
77         mCountY = countY;
78         mBorderSpace = borderSpace;
79     }
80 
getChildAt(int cellX, int cellY)81     public View getChildAt(int cellX, int cellY) {
82         final int count = getChildCount();
83         for (int i = 0; i < count; i++) {
84             View child = getChildAt(i);
85             CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
86 
87             if ((lp.getCellX() <= cellX) && (cellX < lp.getCellX() + lp.cellHSpan)
88                     && (lp.getCellY() <= cellY) && (cellY < lp.getCellY() + lp.cellVSpan)) {
89                 return child;
90             }
91         }
92         return null;
93     }
94 
95     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)96     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
97         int count = getChildCount();
98 
99         int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
100         int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
101         setMeasuredDimension(widthSpecSize, heightSpecSize);
102 
103         for (int i = 0; i < count; i++) {
104             View child = getChildAt(i);
105             if (child.getVisibility() != GONE) {
106                 measureChild(child);
107             }
108         }
109     }
110 
111     /**
112      * Adds view to Layout a new position and it does not trigger a layout request.
113      * For more information check documentation for
114      * {@code ViewGroup#addViewInLayout(View, int, LayoutParams, boolean)}
115      *
116      * @param child view to be added
117      * @return true if the child was added, false otherwise
118      */
addViewInLayout(View child, LayoutParams layoutParams)119     public boolean addViewInLayout(View child, LayoutParams layoutParams) {
120         return super.addViewInLayout(child, -1, layoutParams, true);
121     }
122 
setupLp(View child)123     public void setupLp(View child) {
124         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
125         if (child instanceof NavigableAppWidgetHostView) {
126             DeviceProfile profile = mActivity.getDeviceProfile();
127             ((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
128             final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
129             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
130                     appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect);
131         } else {
132             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
133                     mBorderSpace, null);
134         }
135     }
136 
137     // Set whether or not to invert the layout horizontally if the layout is in RTL mode.
setInvertIfRtl(boolean invert)138     public void setInvertIfRtl(boolean invert) {
139         mInvertIfRtl = invert;
140     }
141 
getCellContentHeight()142     public int getCellContentHeight() {
143         return Math.min(getMeasuredHeight(),
144                 mActivity.getDeviceProfile().getCellContentHeight(mContainerType));
145     }
146 
measureChild(View child)147     public void measureChild(View child) {
148         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
149         final DeviceProfile dp = mActivity.getDeviceProfile();
150 
151         if (child instanceof NavigableAppWidgetHostView) {
152             ((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
153             final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag());
154             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
155                     appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect);
156         } else {
157             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
158                     mBorderSpace, null);
159             // Center the icon/folder
160             int cHeight = getCellContentHeight();
161             int cellPaddingY = dp.isScalableGrid && mContainerType == WORKSPACE
162                     ? dp.cellYPaddingPx
163                     : (int) Math.max(0, ((lp.height - cHeight) / 2f));
164 
165             // No need to add padding when cell layout border spacing is present.
166             boolean noPaddingX =
167                     (dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE)
168                             || (dp.folderCellLayoutBorderSpacePx > 0 && mContainerType == FOLDER)
169                             || (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT);
170             int cellPaddingX = noPaddingX
171                     ? 0
172                     : mContainerType == WORKSPACE
173                             ? dp.workspaceCellPaddingXPx
174                             : (int) (dp.edgeMarginPx / 2f);
175             child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
176         }
177         int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
178         int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
179         child.measure(childWidthMeasureSpec, childheightMeasureSpec);
180     }
181 
invertLayoutHorizontally()182     public boolean invertLayoutHorizontally() {
183         return mInvertIfRtl && Utilities.isRtl(getResources());
184     }
185 
186     @Override
onLayout(boolean changed, int l, int t, int r, int b)187     protected void onLayout(boolean changed, int l, int t, int r, int b) {
188         int count = getChildCount();
189         for (int i = 0; i < count; i++) {
190             final View child = getChildAt(i);
191             if (child.getVisibility() != GONE) {
192                 layoutChild(child);
193             }
194         }
195     }
196 
197     /**
198      * Core logic to layout a child for this ViewGroup.
199      */
layoutChild(View child)200     public void layoutChild(View child) {
201         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
202         if (child instanceof NavigableAppWidgetHostView) {
203             NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child;
204 
205             // Scale and center the widget to fit within its cells.
206             DeviceProfile profile = mActivity.getDeviceProfile();
207             final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
208             float scaleX = appWidgetScale.x;
209             float scaleY = appWidgetScale.y;
210 
211             nahv.setScaleToFit(Math.min(scaleX, scaleY));
212             nahv.getTranslateDelegate().setTranslation(INDEX_WIDGET_CENTERING,
213                     -(lp.width - (lp.width * scaleX)) / 2.0f,
214                     -(lp.height - (lp.height * scaleY)) / 2.0f);
215         }
216 
217         int childLeft = lp.x;
218         int childTop = lp.y;
219         child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
220 
221         if (lp.dropped) {
222             lp.dropped = false;
223 
224             final int[] cellXY = mTmpCellXY;
225             getLocationOnScreen(cellXY);
226             mWallpaperManager.sendWallpaperCommand(getWindowToken(),
227                     WallpaperManager.COMMAND_DROP,
228                     cellXY[0] + childLeft + lp.width / 2,
229                     cellXY[1] + childTop + lp.height / 2, 0, null);
230         }
231     }
232 
233 
234     @Override
onInterceptTouchEvent(MotionEvent ev)235     public boolean onInterceptTouchEvent(MotionEvent ev) {
236         if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) {
237             // Dont let children handle touch, if we are not visible.
238             return true;
239         }
240         return super.onInterceptTouchEvent(ev);
241     }
242 
243     @Override
shouldDelayChildPressedState()244     public boolean shouldDelayChildPressedState() {
245         return false;
246     }
247 
248     @Override
requestChildFocus(View child, View focused)249     public void requestChildFocus(View child, View focused) {
250         super.requestChildFocus(child, focused);
251         if (child != null) {
252             Rect r = new Rect();
253             child.getDrawingRect(r);
254             requestRectangleOnScreen(r);
255         }
256     }
257 
258     @Override
cancelLongPress()259     public void cancelLongPress() {
260         super.cancelLongPress();
261 
262         // Cancel long press for all children
263         final int count = getChildCount();
264         for (int i = 0; i < count; i++) {
265             final View child = getChildAt(i);
266             child.cancelLongPress();
267         }
268     }
269 
270     @Override
drawFolderLeaveBehindForIcon(FolderIcon child)271     public void drawFolderLeaveBehindForIcon(FolderIcon child) {
272         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
273         // While the folder is open, the position of the icon cannot change.
274         lp.canReorder = false;
275         if (mContainerType == HOTSEAT) {
276             CellLayout cl = (CellLayout) getParent();
277             cl.setFolderLeaveBehindCell(lp.getCellX(), lp.getCellY());
278         }
279     }
280 
281     @Override
clearFolderLeaveBehind(FolderIcon child)282     public void clearFolderLeaveBehind(FolderIcon child) {
283         ((CellLayoutLayoutParams) child.getLayoutParams()).canReorder = true;
284         if (mContainerType == HOTSEAT) {
285             CellLayout cl = (CellLayout) getParent();
286             cl.clearFolderLeaveBehind();
287         }
288     }
289 }
290