18c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka/* 28c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * Copyright (C) 2008 The Android Open Source Project 38c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * 48c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 58c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * you may not use this file except in compliance with the License. 68c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * You may obtain a copy of the License at 78c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * 88c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * http://www.apache.org/licenses/LICENSE-2.0 98c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * 108c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * Unless required by applicable law or agreed to in writing, software 118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 128c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * See the License for the specific language governing permissions and 148c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka * limitations under the License. 158c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka */ 168c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 188c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 1941e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyalimport static android.view.MotionEvent.ACTION_DOWN; 2041e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal 218c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurkaimport android.app.WallpaperManager; 228c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurkaimport android.content.Context; 238c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurkaimport android.graphics.Rect; 2441e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyalimport android.view.MotionEvent; 258c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurkaimport android.view.View; 26cf6125c2d30ce02d8ab6cbe8e37a20f6a831e216Michael Jurkaimport android.view.ViewGroup; 278c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 28c13403c612748bfdf06436510600230c4c4b55ecSunny Goyalimport com.android.launcher3.CellLayout.ContainerType; 2929947f0b53eb30c0324204376df001680d4d4ab1Sunny Goyalimport com.android.launcher3.widget.LauncherAppWidgetHostView; 3093e1f04fa915fc22ecccc7e40794472914f3d446Jon Miranda 31a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurkapublic class ShortcutAndWidgetContainer extends ViewGroup { 3293e1f04fa915fc22ecccc7e40794472914f3d446Jon Miranda static final String TAG = "ShortcutAndWidgetContainer"; 3393e1f04fa915fc22ecccc7e40794472914f3d446Jon Miranda 348c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // These are temporary variables to prevent having to allocate a new object just to 358c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 368c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka private final int[] mTmpCellXY = new int[2]; 378c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 38c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal @ContainerType private final int mContainerType; 398c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka private final WallpaperManager mWallpaperManager; 408c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 41d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen private int mCellWidth; 42d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen private int mCellHeight; 43d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 442374abfda3e53f84e005df8923170308e4df8c03Adam Cohen private int mCountX; 452374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 462e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen private Launcher mLauncher; 472374abfda3e53f84e005df8923170308e4df8c03Adam Cohen private boolean mInvertIfRtl = false; 482374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 49c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal public ShortcutAndWidgetContainer(Context context, @ContainerType int containerType) { 508c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka super(context); 512fd020860533e18c64a93d14d11cb2d34bc9cbafTony mLauncher = Launcher.getLauncher(context); 528c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka mWallpaperManager = WallpaperManager.getInstance(context); 53c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal mContainerType = containerType; 542801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 552801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 56aa8a871e337fe42e9339b96833eaf37bf2b64b2fSunny Goyal public void setCellDimensions(int cellWidth, int cellHeight, int countX, int countY) { 578c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka mCellWidth = cellWidth; 588c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka mCellHeight = cellHeight; 592374abfda3e53f84e005df8923170308e4df8c03Adam Cohen mCountX = countX; 608c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 618c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 628c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka public View getChildAt(int x, int y) { 638c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka final int count = getChildCount(); 648c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka for (int i = 0; i < count; i++) { 658c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 668c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 678c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 688c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) && 69f579b5041afe8272c79f9f13001120d37eeeee7bAdam Cohen (lp.cellY <= y) && (y < lp.cellY + lp.cellVSpan)) { 708c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka return child; 718c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 728c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 738c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka return null; 748c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 758c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 768c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka @Override 778c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 788c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 79ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen 80ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 81ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 82ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen setMeasuredDimension(widthSpecSize, heightSpecSize); 83ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen 848c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka for (int i = 0; i < count; i++) { 858c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 862824b0750e978e5a63f804a42e9eedba53e8d21dVladimir Marko if (child.getVisibility() != GONE) { 872824b0750e978e5a63f804a42e9eedba53e8d21dVladimir Marko measureChild(child); 882824b0750e978e5a63f804a42e9eedba53e8d21dVladimir Marko } 898c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 908c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 92e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda public void setupLp(View child) { 93e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 94e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda if (child instanceof LauncherAppWidgetHostView) { 95e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda DeviceProfile profile = mLauncher.getDeviceProfile(); 96e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, 97e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda profile.appWidgetScale.x, profile.appWidgetScale.y); 98e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda } else { 99e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX); 100e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda } 1012374abfda3e53f84e005df8923170308e4df8c03Adam Cohen } 1022374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 1032374abfda3e53f84e005df8923170308e4df8c03Adam Cohen // Set whether or not to invert the layout horizontally if the layout is in RTL mode. 1042374abfda3e53f84e005df8923170308e4df8c03Adam Cohen public void setInvertIfRtl(boolean invert) { 1052374abfda3e53f84e005df8923170308e4df8c03Adam Cohen mInvertIfRtl = invert; 106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1080b754e564b6a5fef535815467464a6abaa84d434Sunny Goyal public int getCellContentHeight() { 109c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal return Math.min(getMeasuredHeight(), 110c13403c612748bfdf06436510600230c4c4b55ecSunny Goyal mLauncher.getDeviceProfile().getCellHeight(mContainerType)); 11169737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung } 11269737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung 113d5e42733799817d11d739b0a882da8dda721126dAdam Cohen public void measureChild(View child) { 114d5e42733799817d11d739b0a882da8dda721126dAdam Cohen CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 1157ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal final DeviceProfile profile = mLauncher.getDeviceProfile(); 1167ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal 1177ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal if (child instanceof LauncherAppWidgetHostView) { 1187ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, 1197ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal profile.appWidgetScale.x, profile.appWidgetScale.y); 1207ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal // Widgets have their own padding 121ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen } else { 1227ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX); 1237ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal // Center the icon/folder 1247ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal int cHeight = getCellContentHeight(); 1257ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f)); 1267ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal int cellPaddingX = mContainerType == CellLayout.WORKSPACE 1277ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal ? profile.workspaceCellPaddingXPx 1287ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal : (int) (profile.edgeMarginPx / 2f); 1297ce471bdf6d77c9d5778810d9ea033313c579067Sunny Goyal child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0); 130ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen } 131d5e42733799817d11d739b0a882da8dda721126dAdam Cohen int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); 132a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 133d5e42733799817d11d739b0a882da8dda721126dAdam Cohen child.measure(childWidthMeasureSpec, childheightMeasureSpec); 134d5e42733799817d11d739b0a882da8dda721126dAdam Cohen } 135d5e42733799817d11d739b0a882da8dda721126dAdam Cohen 136fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal public boolean invertLayoutHorizontally() { 1377066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal return mInvertIfRtl && Utilities.isRtl(getResources()); 1382374abfda3e53f84e005df8923170308e4df8c03Adam Cohen } 1392374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 1408c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka @Override 1418c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 1428c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 1438c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka for (int i = 0; i < count; i++) { 1448c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka final View child = getChildAt(i); 1458c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (child.getVisibility() != GONE) { 1468c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 1477ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda 1487ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda if (child instanceof LauncherAppWidgetHostView) { 1492126691ce23b4c62e6d17cb9643faf4c2b3886daJon Miranda LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child; 1502126691ce23b4c62e6d17cb9643faf4c2b3886daJon Miranda 1517ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda // Scale and center the widget to fit within its cells. 1527ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda DeviceProfile profile = mLauncher.getDeviceProfile(); 1537ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda float scaleX = profile.appWidgetScale.x; 1547ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda float scaleY = profile.appWidgetScale.y; 1557ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda 1562126691ce23b4c62e6d17cb9643faf4c2b3886daJon Miranda lahv.setScaleToFit(Math.min(scaleX, scaleY)); 1572126691ce23b4c62e6d17cb9643faf4c2b3886daJon Miranda lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f, 1582126691ce23b4c62e6d17cb9643faf4c2b3886daJon Miranda -(lp.height - (lp.height * scaleY)) / 2.0f); 1597ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda } 1607ae64ffbe11a629e54ced0c5c99cd47228b28821Jon Miranda 1618c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int childLeft = lp.x; 1628c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int childTop = lp.y; 1638c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height); 1648c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 1658c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (lp.dropped) { 1668c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka lp.dropped = false; 1678c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 1688c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka final int[] cellXY = mTmpCellXY; 1698c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka getLocationOnScreen(cellXY); 1708c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka mWallpaperManager.sendWallpaperCommand(getWindowToken(), 1718c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka WallpaperManager.COMMAND_DROP, 1728c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka cellXY[0] + childLeft + lp.width / 2, 1738c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka cellXY[1] + childTop + lp.height / 2, 0, null); 1748c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 1758c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 1768c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 1778c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 1788c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 1798c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka @Override 18041e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal public boolean onInterceptTouchEvent(MotionEvent ev) { 18141e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) { 18241e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal // Dont let children handle touch, if we are not visible. 18341e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal return true; 18441e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal } 18541e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal return super.onInterceptTouchEvent(ev); 18641e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal } 18741e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal 18841e7328cb5c32bba713f88296cb0fa5e618274b1Sunny Goyal @Override 189e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 190e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 191e6235dd225404239b55c459245543f3302326112Michael Jurka } 192e6235dd225404239b55c459245543f3302326112Michael Jurka 193e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 1948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka public void requestChildFocus(View child, View focused) { 1958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka super.requestChildFocus(child, focused); 1968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (child != null) { 1978c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka Rect r = new Rect(); 1988c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka child.getDrawingRect(r); 1998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka requestRectangleOnScreen(r); 2008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 2018c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 2028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 2038c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka @Override 2048c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka public void cancelLongPress() { 2058c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka super.cancelLongPress(); 2068c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka 2078c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Cancel long press for all children 2088c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka final int count = getChildCount(); 2098c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka for (int i = 0; i < count; i++) { 2108c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka final View child = getChildAt(i); 2118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka child.cancelLongPress(); 2128c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 2138c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 214d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen} 215