• 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.os.Trace;
32 import android.view.MotionEvent;
33 import android.view.View;
34 import android.view.ViewGroup;
35 
36 import com.android.launcher3.CellLayout.ContainerType;
37 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
38 import com.android.launcher3.folder.FolderIcon;
39 import com.android.launcher3.model.data.ItemInfo;
40 import com.android.launcher3.views.ActivityContext;
41 import com.android.launcher3.widget.NavigableAppWidgetHostView;
42 
43 public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.FolderIconParent {
44     static final String TAG = "ShortcutAndWidgetContainer";
45 
46     // These are temporary variables to prevent having to allocate a new object just to
47     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
48     private final int[] mTmpCellXY = new int[2];
49 
50     @ContainerType
51     private final int mContainerType;
52     private final WallpaperManager mWallpaperManager;
53 
54     private int mCellWidth;
55     private int mCellHeight;
56     private Point mBorderSpace;
57 
58     private int mCountX;
59     private int mCountY;
60 
61     private final ActivityContext mActivity;
62     private boolean mInvertIfRtl = false;
63 
ShortcutAndWidgetContainer(Context context, @ContainerType int containerType)64     public ShortcutAndWidgetContainer(Context context, @ContainerType int containerType) {
65         super(context);
66         mActivity = ActivityContext.lookupContext(context);
67         mWallpaperManager = WallpaperManager.getInstance(context);
68         mContainerType = containerType;
69         setClipChildren(false);
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             final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
128             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
129                     appWidgetScale.x, appWidgetScale.y, mBorderSpace, profile.widgetPadding);
130         } else {
131             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
132                     mBorderSpace);
133         }
134     }
135 
136     // Set whether or not to invert the layout horizontally if the layout is in RTL mode.
setInvertIfRtl(boolean invert)137     public void setInvertIfRtl(boolean invert) {
138         mInvertIfRtl = invert;
139     }
140 
getCellContentHeight()141     public int getCellContentHeight() {
142         return Math.min(getMeasuredHeight(),
143                 mActivity.getDeviceProfile().getCellContentHeight(mContainerType));
144     }
145 
measureChild(View child)146     public void measureChild(View child) {
147         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
148         final DeviceProfile dp = mActivity.getDeviceProfile();
149 
150         if (child instanceof NavigableAppWidgetHostView) {
151             final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag());
152             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
153                     appWidgetScale.x, appWidgetScale.y, mBorderSpace, dp.widgetPadding);
154         } else {
155             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
156                     mBorderSpace);
157             // Center the icon/folder
158             int cHeight = getCellContentHeight();
159             int cellPaddingY =
160                     dp.cellYPaddingPx >= 0 && mContainerType == WORKSPACE
161                             ? dp.cellYPaddingPx
162                             : (int) Math.max(0, ((lp.height - cHeight) / 2f));
163 
164             // No need to add padding when cell layout border spacing is present.
165             boolean noPaddingX =
166                     (dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE)
167                             || (dp.folderCellLayoutBorderSpacePx.x > 0 && mContainerType == FOLDER)
168                             || (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT);
169             int cellPaddingX = noPaddingX
170                     ? 0
171                     : mContainerType == WORKSPACE
172                             ? dp.workspaceCellPaddingXPx
173                             : (int) (dp.edgeMarginPx / 2f);
174             child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
175         }
176         int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
177         int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
178         child.measure(childWidthMeasureSpec, childheightMeasureSpec);
179     }
180 
invertLayoutHorizontally()181     public boolean invertLayoutHorizontally() {
182         return mInvertIfRtl && Utilities.isRtl(getResources());
183     }
184 
185     @Override
onLayout(boolean changed, int l, int t, int r, int b)186     protected void onLayout(boolean changed, int l, int t, int r, int b) {
187         Trace.beginSection("ShortcutAndWidgetConteiner#onLayout");
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         Trace.endSection();
196     }
197 
198     /**
199      * Core logic to layout a child for this ViewGroup.
200      */
layoutChild(View child)201     public void layoutChild(View child) {
202         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
203         if (child instanceof NavigableAppWidgetHostView) {
204             NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child;
205 
206             // Scale and center the widget to fit within its cells.
207             DeviceProfile profile = mActivity.getDeviceProfile();
208             final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
209             float scaleX = appWidgetScale.x;
210             float scaleY = appWidgetScale.y;
211 
212             nahv.setScaleToFit(Math.min(scaleX, scaleY));
213             nahv.getTranslateDelegate().setTranslation(INDEX_WIDGET_CENTERING,
214                     -(lp.width - (lp.width * scaleX)) / 2.0f,
215                     -(lp.height - (lp.height * scaleY)) / 2.0f);
216         }
217 
218         int childLeft = lp.x;
219         int childTop = lp.y;
220         child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
221 
222         if (lp.dropped) {
223             lp.dropped = false;
224 
225             final int[] cellXY = mTmpCellXY;
226             getLocationOnScreen(cellXY);
227             mWallpaperManager.sendWallpaperCommand(getWindowToken(),
228                     WallpaperManager.COMMAND_DROP,
229                     cellXY[0] + childLeft + lp.width / 2,
230                     cellXY[1] + childTop + lp.height / 2, 0, null);
231         }
232     }
233 
234 
235     @Override
onInterceptTouchEvent(MotionEvent ev)236     public boolean onInterceptTouchEvent(MotionEvent ev) {
237         if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) {
238             // Dont let children handle touch, if we are not visible.
239             return true;
240         }
241         return super.onInterceptTouchEvent(ev);
242     }
243 
244     @Override
shouldDelayChildPressedState()245     public boolean shouldDelayChildPressedState() {
246         return false;
247     }
248 
249     @Override
requestChildFocus(View child, View focused)250     public void requestChildFocus(View child, View focused) {
251         super.requestChildFocus(child, focused);
252         if (child != null) {
253             Rect r = new Rect();
254             child.getDrawingRect(r);
255             requestRectangleOnScreen(r);
256         }
257     }
258 
259     @Override
cancelLongPress()260     public void cancelLongPress() {
261         super.cancelLongPress();
262 
263         // Cancel long press for all children
264         final int count = getChildCount();
265         for (int i = 0; i < count; i++) {
266             final View child = getChildAt(i);
267             child.cancelLongPress();
268         }
269     }
270 
271     @Override
drawFolderLeaveBehindForIcon(FolderIcon child)272     public void drawFolderLeaveBehindForIcon(FolderIcon child) {
273         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
274         // While the folder is open, the position of the icon cannot change.
275         lp.canReorder = false;
276         if (mContainerType == HOTSEAT) {
277             CellLayout cl = (CellLayout) getParent();
278             cl.setFolderLeaveBehindCell(lp.getCellX(), lp.getCellY());
279         }
280     }
281 
282     @Override
clearFolderLeaveBehind(FolderIcon child)283     public void clearFolderLeaveBehind(FolderIcon child) {
284         ((CellLayoutLayoutParams) child.getLayoutParams()).canReorder = true;
285         if (mContainerType == HOTSEAT) {
286             CellLayout cl = (CellLayout) getParent();
287             cl.clearFolderLeaveBehind();
288         }
289     }
290 }
291