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