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 android.app.WallpaperManager; 20 import android.content.Context; 21 import android.graphics.Canvas; 22 import android.graphics.Paint; 23 import android.graphics.Rect; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.view.ViewGroup.LayoutParams; 27 28 public 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