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
17package com.android.launcher3;
18
19import android.app.WallpaperManager;
20import android.content.Context;
21import android.graphics.Canvas;
22import android.graphics.Paint;
23import android.graphics.Rect;
24import android.view.View;
25import android.view.ViewGroup;
26
27public class ShortcutAndWidgetContainer extends ViewGroup {
28    static final String TAG = "CellLayoutChildren";
29
30    // These are temporary variables to prevent having to allocate a new object just to
31    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
32    private final int[] mTmpCellXY = new int[2];
33
34    private final WallpaperManager mWallpaperManager;
35
36    private boolean mIsHotseatLayout;
37
38    private int mCellWidth;
39    private int mCellHeight;
40
41    private int mWidthGap;
42    private int mHeightGap;
43
44    private int mCountX;
45    private int mCountY;
46
47    private boolean mInvertIfRtl = false;
48
49    public ShortcutAndWidgetContainer(Context context) {
50        super(context);
51        mWallpaperManager = WallpaperManager.getInstance(context);
52    }
53
54    public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap,
55            int countX, int countY) {
56        mCellWidth = cellWidth;
57        mCellHeight = cellHeight;
58        mWidthGap = widthGap;
59        mHeightGap = heightGap;
60        mCountX = countX;
61        mCountY = countY;
62    }
63
64    public View getChildAt(int x, int y) {
65        final int count = getChildCount();
66        for (int i = 0; i < count; i++) {
67            View child = getChildAt(i);
68            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
69
70            if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
71                    (lp.cellY <= y) && (y < lp.cellY + lp.cellVSpan)) {
72                return child;
73            }
74        }
75        return null;
76    }
77
78    @Override
79    protected void dispatchDraw(Canvas canvas) {
80        @SuppressWarnings("all") // suppress dead code warning
81        final boolean debug = false;
82        if (debug) {
83            // Debug drawing for hit space
84            Paint p = new Paint();
85            p.setColor(0x6600FF00);
86            for (int i = getChildCount() - 1; i >= 0; i--) {
87                final View child = getChildAt(i);
88                final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
89
90                canvas.drawRect(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height, p);
91            }
92        }
93        super.dispatchDraw(canvas);
94    }
95
96    @Override
97    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
98        int count = getChildCount();
99
100        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
101        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
102        setMeasuredDimension(widthSpecSize, heightSpecSize);
103
104        for (int i = 0; i < count; i++) {
105            View child = getChildAt(i);
106            if (child.getVisibility() != GONE) {
107                measureChild(child);
108            }
109        }
110    }
111
112    public void setupLp(CellLayout.LayoutParams lp) {
113        lp.setup(mCellWidth, mCellHeight, mWidthGap, mHeightGap, invertLayoutHorizontally(),
114                mCountX);
115    }
116
117    // Set whether or not to invert the layout horizontally if the layout is in RTL mode.
118    public void setInvertIfRtl(boolean invert) {
119        mInvertIfRtl = invert;
120    }
121
122    public void setIsHotseat(boolean isHotseat) {
123        mIsHotseatLayout = isHotseat;
124    }
125
126    int getCellContentWidth() {
127        final LauncherAppState app = LauncherAppState.getInstance();
128        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
129        return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
130                grid.hotseatCellWidthPx: grid.cellWidthPx);
131    }
132
133    int getCellContentHeight() {
134        final LauncherAppState app = LauncherAppState.getInstance();
135        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
136        return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
137                grid.hotseatCellHeightPx : grid.cellHeightPx);
138    }
139
140    public void measureChild(View child) {
141        final LauncherAppState app = LauncherAppState.getInstance();
142        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
143        final int cellWidth = mCellWidth;
144        final int cellHeight = mCellHeight;
145        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
146        if (!lp.isFullscreen) {
147            lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, invertLayoutHorizontally(),
148                    mCountX);
149
150            if (child instanceof LauncherAppWidgetHostView) {
151                // Widgets have their own padding, so skip
152            } else {
153                // Otherwise, center the icon
154                int cHeight = getCellContentHeight();
155                int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
156                int cellPaddingX = (int) (grid.edgeMarginPx / 2f);
157                child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
158            }
159        } else {
160            lp.x = 0;
161            lp.y = 0;
162            lp.width = getMeasuredWidth();
163            lp.height = getMeasuredHeight();
164        }
165        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
166        int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
167                MeasureSpec.EXACTLY);
168        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
169    }
170
171    private boolean invertLayoutHorizontally() {
172        return mInvertIfRtl && isLayoutRtl();
173    }
174
175    public boolean isLayoutRtl() {
176        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
177    }
178
179    @Override
180    protected void onLayout(boolean changed, int l, int t, int r, int b) {
181        int count = getChildCount();
182        for (int i = 0; i < count; i++) {
183            final View child = getChildAt(i);
184            if (child.getVisibility() != GONE) {
185                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
186                int childLeft = lp.x;
187                int childTop = lp.y;
188                child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
189
190                if (lp.dropped) {
191                    lp.dropped = false;
192
193                    final int[] cellXY = mTmpCellXY;
194                    getLocationOnScreen(cellXY);
195                    mWallpaperManager.sendWallpaperCommand(getWindowToken(),
196                            WallpaperManager.COMMAND_DROP,
197                            cellXY[0] + childLeft + lp.width / 2,
198                            cellXY[1] + childTop + lp.height / 2, 0, null);
199                }
200            }
201        }
202    }
203
204    @Override
205    public boolean shouldDelayChildPressedState() {
206        return false;
207    }
208
209    @Override
210    public void requestChildFocus(View child, View focused) {
211        super.requestChildFocus(child, focused);
212        if (child != null) {
213            Rect r = new Rect();
214            child.getDrawingRect(r);
215            requestRectangleOnScreen(r);
216        }
217    }
218
219    @Override
220    public void cancelLongPress() {
221        super.cancelLongPress();
222
223        // Cancel long press for all children
224        final int count = getChildCount();
225        for (int i = 0; i < count; i++) {
226            final View child = getChildAt(i);
227            child.cancelLongPress();
228        }
229    }
230
231    @Override
232    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
233        final int count = getChildCount();
234        for (int i = 0; i < count; i++) {
235            final View view = getChildAt(i);
236            view.setDrawingCacheEnabled(enabled);
237            // Update the drawing caches
238            if (!view.isHardwareAccelerated() && enabled) {
239                view.buildDrawingCache(true);
240            }
241        }
242    }
243
244    @Override
245    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
246        super.setChildrenDrawnWithCacheEnabled(enabled);
247    }
248}
249