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