DragView.java revision 1bce7fd342875be8f7c1f82c8cf21d0199c8d544
100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato/*
200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * Copyright (C) 2008 The Android Open Source Project
300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato *
400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * Licensed under the Apache License, Version 2.0 (the "License");
500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * you may not use this file except in compliance with the License.
600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * You may obtain a copy of the License at
700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato *
800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato *      http://www.apache.org/licenses/LICENSE-2.0
900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato *
1000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * Unless required by applicable law or agreed to in writing, software
1100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * distributed under the License is distributed on an "AS IS" BASIS,
1200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * See the License for the specific language governing permissions and
1400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato * limitations under the License.
1500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato */
1600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
17fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevpackage com.android.launcher3.dragndrop;
1800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
19d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshevimport android.animation.Animator;
20d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshevimport android.animation.AnimatorListenerAdapter;
21fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.animation.FloatArrayEvaluator;
22a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroyimport android.animation.ValueAnimator;
23a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2442e28092b336bf89bee94c61e2cd327e1d8ec882Sunny Goyalimport android.annotation.SuppressLint;
25fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.annotation.TargetApi;
26de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.content.res.Resources;
2700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Bitmap;
2800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Canvas;
29fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.graphics.Color;
30fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.graphics.ColorMatrix;
31fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.graphics.ColorMatrixColorFilter;
3200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Paint;
33b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chungimport android.graphics.Point;
34e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohenimport android.graphics.Rect;
35fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.os.Build;
3600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.view.View;
37a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroyimport android.view.animation.DecelerateInterpolator;
38fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshev
39fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Launcher;
40fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.LauncherAnimUtils;
41fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Utilities;
42e0c332365604976d999eb25d4bdcc49ec75b7a1cTony Wickhamimport com.android.launcher3.config.FeatureFlags;
43091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
44fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshev
45fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.R;
46fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshev
47fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport java.util.Arrays;
48fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
49a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroypublic class DragView extends View {
503a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal    public static int COLOR_CHANGE_DURATION = 120;
51fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
52091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk static float sDragAlpha = 1f;
537bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
5400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private Bitmap mBitmap;
55ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    private Bitmap mCrossFadeBitmap;
56316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk Paint mPaint;
57d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final int mRegistrationX;
58d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final int mRegistrationY;
5900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
60b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    private Point mDragVisualizeOffset = null;
61e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private Rect mDragRegion = null;
62d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final DragLayer mDragLayer;
6342e28092b336bf89bee94c61e2cd327e1d8ec882Sunny Goyal    @Thunk final DragController mDragController;
64fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    private boolean mHasDrawn = false;
65091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk float mCrossFadeProgress = 0f;
66456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev    private boolean mAnimationCancelled = false;
67a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
68a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy    ValueAnimator mAnim;
69eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
70eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    // size.  This is ignored for non-icons.
71eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    private float mIntrinsicIconScale = 1f;
7200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
73316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk float[] mCurrentFilter;
74fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    private ValueAnimator mFilterAnimator;
75fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
7600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
7700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Construct the drag view.
7800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * <p>
7900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * The registration point is the point inside our view that the touch events should
8000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * be centered upon.
818dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param launcher The Launcher instance
8200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param bitmap The view that we're dragging around.  We scale it up when we draw it.
8300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param registrationX The x coordinate of the registration point.
8400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param registrationY The y coordinate of the registration point.
8500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
867066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
871bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY, int left,
881bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham            int top, int width, int height, final float initialScale, final float finalScaleDps) {
898dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        super(launcher);
908dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragLayer = launcher.getDragLayer();
91d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        mDragController = launcher.getDragController();
9200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
931bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham        final float scale = (width + finalScaleDps) / width;
94a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
95307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // Set the initial scale to avoid any jumps
96307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        setScaleX(initialScale);
97307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        setScaleY(initialScale);
98307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
99a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        // Animate the view into the correct position
100f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        mAnim = LauncherAnimUtils.ofFloat(this, 0f, 1f);
1017bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        mAnim.setDuration(150);
102a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mAnim.addUpdateListener(new AnimatorUpdateListener() {
103a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            @Override
104a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            public void onAnimationUpdate(ValueAnimator animation) {
105a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                final float value = (Float) animation.getAnimatedValue();
106a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
10772d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                setScaleX(initialScale + (value * (scale - initialScale)));
10872d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                setScaleY(initialScale + (value * (scale - initialScale)));
109867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                if (sDragAlpha != 1f) {
110867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                    setAlpha(sDragAlpha * value + (1f - value));
111867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                }
112a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
113a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                if (getParent() == null) {
114a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                    animation.cancel();
115a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                }
116a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            }
117a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        });
11800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
119d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        mAnim.addListener(new AnimatorListenerAdapter() {
120d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            @Override
121d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            public void onAnimationEnd(Animator animation) {
122456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                if (!mAnimationCancelled) {
123456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                    mDragController.onDragViewAnimationEnd();
124456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                }
125d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            }
126d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        });
127d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
1287bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
129e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        setDragRegion(new Rect(0, 0, width, height));
13000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
13100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // The point in our scaled bitmap that the touch events are located
132a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mRegistrationX = registrationX;
133a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mRegistrationY = registrationY;
13462bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy
13562bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
13662bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
13762bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        measure(ms, ms);
1386cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
13975deaf3d8f369bd13ea59ec3740324a5cfeb3099Sunny Goyal
1409fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal        if (Utilities.ATLEAST_LOLLIPOP) {
14175deaf3d8f369bd13ea59ec3740324a5cfeb3099Sunny Goyal            setElevation(getResources().getDimension(R.dimen.drag_elevation));
14275deaf3d8f369bd13ea59ec3740324a5cfeb3099Sunny Goyal        }
14362bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy    }
14462bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy
145eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    /** Sets the scale of the view over the normal workspace icon size. */
146eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    public void setIntrinsicIconScaleFactor(float scale) {
147eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        mIntrinsicIconScale = scale;
148eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    }
149eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung
150eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    public float getIntrinsicIconScaleFactor() {
151eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        return mIntrinsicIconScale;
152eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    }
153eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung
154a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionLeft() {
155e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.left;
156a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
157a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
158a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionTop() {
159e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.top;
160a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
161a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
162a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionWidth() {
163e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.width();
164a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
165a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
166a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionHeight() {
167e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.height();
168e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
169e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
170b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    public void setDragVisualizeOffset(Point p) {
171b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragVisualizeOffset = p;
172b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    }
173b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung
174b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    public Point getDragVisualizeOffset() {
175b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        return mDragVisualizeOffset;
176b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    }
177b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung
178e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    public void setDragRegion(Rect r) {
179e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        mDragRegion = r;
180e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
181e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
182e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    public Rect getDragRegion() {
183e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion;
184a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
185a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    @Override
18700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
188eebd92496e2fbfbd81ea871862a681929101ba06Joe Onorato        setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
18900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
19000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
191d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    // Draws drag shadow for system DND.
19242e28092b336bf89bee94c61e2cd327e1d8ec882Sunny Goyal    @SuppressLint("WrongCall")
193d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    public void drawDragShadow(Canvas canvas) {
194d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
195d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        canvas.scale(getScaleX(), getScaleY());
196d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        onDraw(canvas);
197d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        canvas.restoreToCount(saveCount);
198d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    }
199d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
200d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    // Provides drag shadow metrics for system DND.
201d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    public void provideDragShadowMetrics(Point size, Point touch) {
202d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
203d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
20437bd006b73b4399ba10bb46e7f57a56b2e133e86Vadim Tryshev        final float xGrowth = mBitmap.getWidth() * (getScaleX() - 1);
20537bd006b73b4399ba10bb46e7f57a56b2e133e86Vadim Tryshev        final float yGrowth = mBitmap.getHeight() * (getScaleY() - 1);
2069430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev        touch.set(
2079430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev                mRegistrationX + (int)Math.round(xGrowth / 2),
2089430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev                mRegistrationY + (int)Math.round(yGrowth / 2));
209d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    }
210d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
21100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    @Override
21200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    protected void onDraw(Canvas canvas) {
213fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        mHasDrawn = true;
214ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
215ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        if (crossFade) {
216ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
217ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            mPaint.setAlpha(alpha);
218ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
21900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
220ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        if (crossFade) {
221ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            mPaint.setAlpha((int) (255 * mCrossFadeProgress));
222d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
223ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
224ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
225ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            canvas.scale(sX, sY);
226ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
227d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            canvas.restoreToCount(saveCount);
228ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
229ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
230ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
231ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
232ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mCrossFadeBitmap = crossFadeBitmap;
233ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
234ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
235ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void crossFade(int duration) {
236f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1f);
237ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.setDuration(duration);
238ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.setInterpolator(new DecelerateInterpolator(1.5f));
239ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.addUpdateListener(new AnimatorUpdateListener() {
240ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            @Override
241ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
242ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                mCrossFadeProgress = animation.getAnimatedFraction();
2435d2fc32e6da66f877dfba4fe513fbabdcdae5f99Sunny Goyal                invalidate();
244ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            }
245ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        });
246ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.start();
24700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
24800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
24961967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung    public void setColor(int color) {
2506cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        if (mPaint == null) {
2516cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka            mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
2526cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        }
25361967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        if (color != 0) {
254fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            ColorMatrix m1 = new ColorMatrix();
255fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            m1.setSaturation(0);
256fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
257fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            ColorMatrix m2 = new ColorMatrix();
2583a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal            setColorScale(color, m2);
259fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            m1.postConcat(m2);
260fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
2619fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal            if (Utilities.ATLEAST_LOLLIPOP) {
262fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                animateFilterTo(m1.getArray());
263fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            } else {
264fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
265fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                invalidate();
266fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            }
26761967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        } else {
2689fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal            if (!Utilities.ATLEAST_LOLLIPOP || mCurrentFilter == null) {
269fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                mPaint.setColorFilter(null);
270fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                invalidate();
271fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            } else {
272fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                animateFilterTo(new ColorMatrix().getArray());
273fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            }
27461967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        }
275fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    }
276fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
277fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
278fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    private void animateFilterTo(float[] targetFilter) {
279fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
280fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
281fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
282fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        if (mFilterAnimator != null) {
283fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            mFilterAnimator.cancel();
284fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        }
285fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
286fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                oldFilter, targetFilter);
287fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
288fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
289fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
290fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            @Override
291fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            public void onAnimationUpdate(ValueAnimator animation) {
292fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
293fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                invalidate();
294fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            }
295fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        });
296fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.start();
29700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
29800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
299fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    public boolean hasDrawn() {
300fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        return mHasDrawn;
301fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    }
302fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
3033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    @Override
3043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void setAlpha(float alpha) {
3053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        super.setAlpha(alpha);
3063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mPaint.setAlpha((int) (255 * alpha));
3073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        invalidate();
3083e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
3093e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
31000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
31100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Create a window containing this view and show it.
31200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
31300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param windowToken obtained from v.getWindowToken() from one of your views
3148dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchX the x coordinate the user touched in DragLayer coordinates
3158dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchY the y coordinate the user touched in DragLayer coordinates
31600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
3178dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public void show(int touchX, int touchY) {
3188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragLayer.addView(this);
319043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
320043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Start the pick-up animation
3218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
3228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.width = mBitmap.getWidth();
3238dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.height = mBitmap.getHeight();
3248dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.customPosition = true;
3258dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        setLayoutParams(lp);
3267bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        setTranslationX(touchX - mRegistrationX);
3277bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        setTranslationY(touchY - mRegistrationY);
328ca99383daef92fed673de22126875cb485be494fMichael Jurka        // Post the animation to skip other expensive work happening on the first frame
329ca99383daef92fed673de22126875cb485be494fMichael Jurka        post(new Runnable() {
330a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham            public void run() {
331a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham                mAnim.start();
332a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham            }
333a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham        });
33400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
335716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3367bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void cancelAnimation() {
337456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev        mAnimationCancelled = true;
3387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mAnim != null && mAnim.isRunning()) {
3397bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mAnim.cancel();
3407bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
3417bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    }
3427bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
34300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
34400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Move the window containing this view.
34500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
3468dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchX the x coordinate the user touched in DragLayer coordinates
3478dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchY the y coordinate the user touched in DragLayer coordinates
34800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
3491bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public void move(int touchX, int touchY) {
350d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        setTranslationX(touchX - mRegistrationX);
351d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        setTranslationY(touchY - mRegistrationY);
35200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
35300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
3541bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public void remove() {
3557bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (getParent() != null) {
3567bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDragLayer.removeView(DragView.this);
3577bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
3586f13342ffd3f968de9ff86b988621cc91d94adffPatrick Dubroy    }
3593a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal
3603a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal    public static void setColorScale(int color, ColorMatrix target) {
3613a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal        target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
3623a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal                Color.blue(color) / 255f, Color.alpha(color) / 255f);
3633a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal    }
36400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato}
365