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