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;
2500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Bitmap;
2600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Canvas;
27fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.graphics.ColorMatrix;
28fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport android.graphics.ColorMatrixColorFilter;
2900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.graphics.Paint;
30b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chungimport android.graphics.Point;
31e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohenimport android.graphics.Rect;
3200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onoratoimport android.view.View;
33a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroyimport android.view.animation.DecelerateInterpolator;
34fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshev
35fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.Launcher;
36fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshevimport com.android.launcher3.LauncherAnimUtils;
37ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickhamimport com.android.launcher3.R;
386c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickhamimport com.android.launcher3.util.Themes;
39091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
40fedca43d396d6fd7c46fbb2f37dfa7cfe3b31834Vadim Tryshev
41fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyalimport java.util.Arrays;
42fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
43a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroypublic class DragView extends View {
44a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public static final int COLOR_CHANGE_DURATION = 120;
45a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public static final int VIEW_ZOOM_DURATION = 150;
46fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
47091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk static float sDragAlpha = 1f;
487bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
4900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private Bitmap mBitmap;
50ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    private Bitmap mCrossFadeBitmap;
51316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk Paint mPaint;
52c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda    private final int mBlurSizeOutline;
53d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final int mRegistrationX;
54d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final int mRegistrationY;
55ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham    private final float mInitialScale;
56ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham    private final int[] mTempLoc = new int[2];
5700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
58b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    private Point mDragVisualizeOffset = null;
59e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private Rect mDragRegion = null;
60d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    private final DragLayer mDragLayer;
6142e28092b336bf89bee94c61e2cd327e1d8ec882Sunny Goyal    @Thunk final DragController mDragController;
62fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    private boolean mHasDrawn = false;
63091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk float mCrossFadeProgress = 0f;
64456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev    private boolean mAnimationCancelled = false;
65a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
66a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy    ValueAnimator mAnim;
67eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
68eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    // size.  This is ignored for non-icons.
69eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    private float mIntrinsicIconScale = 1f;
7000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
71316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk float[] mCurrentFilter;
72fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    private ValueAnimator mFilterAnimator;
73fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
74a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private int mLastTouchX;
75a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private int mLastTouchY;
76a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private int mAnimatedShiftX;
77a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private int mAnimatedShiftY;
78a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
7900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
8000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Construct the drag view.
8100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * <p>
8200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * The registration point is the point inside our view that the touch events should
8300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * be centered upon.
848dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param launcher The Launcher instance
8500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param bitmap The view that we're dragging around.  We scale it up when we draw it.
8600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param registrationX The x coordinate of the registration point.
8700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * @param registrationY The y coordinate of the registration point.
8800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
89157793dda450b69da388b859d1c1a7a1083c4ec9Sunny Goyal    public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
90157793dda450b69da388b859d1c1a7a1083c4ec9Sunny Goyal                    final float initialScale, final float finalScaleDps) {
918dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        super(launcher);
928dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragLayer = launcher.getDragLayer();
93d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        mDragController = launcher.getDragController();
9400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
95157793dda450b69da388b859d1c1a7a1083c4ec9Sunny Goyal        final float scale = (bitmap.getWidth() + finalScaleDps) / bitmap.getWidth();
96a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
97307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        // Set the initial scale to avoid any jumps
98307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        setScaleX(initialScale);
99307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        setScaleY(initialScale);
100307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
101a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        // Animate the view into the correct position
102cda3bfb2e1d89ad872558dd0a82ae79ca6fe41eaJon Miranda        mAnim = LauncherAnimUtils.ofFloat(0f, 1f);
103a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mAnim.setDuration(VIEW_ZOOM_DURATION);
104a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mAnim.addUpdateListener(new AnimatorUpdateListener() {
105a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            @Override
106a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            public void onAnimationUpdate(ValueAnimator animation) {
107a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                final float value = (Float) animation.getAnimatedValue();
108a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
10972d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                setScaleX(initialScale + (value * (scale - initialScale)));
11072d598400da7cef9c7fc4f99bb1fcd7ff0710011Winson Chung                setScaleY(initialScale + (value * (scale - initialScale)));
111867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                if (sDragAlpha != 1f) {
112867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                    setAlpha(sDragAlpha * value + (1f - value));
113867ca62c0e4b811d46734ff940d59c7a787525c8Winson Chung                }
114a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy
115a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                if (getParent() == null) {
116a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                    animation.cancel();
117a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy                }
118a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy            }
119a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        });
12000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
121d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        mAnim.addListener(new AnimatorListenerAdapter() {
122d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            @Override
123d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            public void onAnimationEnd(Animator animation) {
124456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                if (!mAnimationCancelled) {
125456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                    mDragController.onDragViewAnimationEnd();
126456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev                }
127d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            }
128d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        });
129d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
130157793dda450b69da388b859d1c1a7a1083c4ec9Sunny Goyal        mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());
131157793dda450b69da388b859d1c1a7a1083c4ec9Sunny Goyal        setDragRegion(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()));
13200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
13300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        // The point in our scaled bitmap that the touch events are located
134a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mRegistrationX = registrationX;
135a669d79d0dcf034651ce305a8cd334272bec3374Patrick Dubroy        mRegistrationY = registrationY;
13662bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy
137ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham        mInitialScale = initialScale;
138ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham
13962bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
14062bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
14162bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy        measure(ms, ms);
1426cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
14375deaf3d8f369bd13ea59ec3740324a5cfeb3099Sunny Goyal
144c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda        mBlurSizeOutline = getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
145c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda
146a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal        setElevation(getResources().getDimension(R.dimen.drag_elevation));
14762bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy    }
14862bbb3c573fe902940431e4b957c0c4918358d36Patrick Dubroy
149eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    /** Sets the scale of the view over the normal workspace icon size. */
150eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    public void setIntrinsicIconScaleFactor(float scale) {
151eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        mIntrinsicIconScale = scale;
152eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    }
153eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung
154eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    public float getIntrinsicIconScaleFactor() {
155eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung        return mIntrinsicIconScale;
156eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung    }
157eeb5bbc9409978cc2ae52d48380399fcde3d9f85Winson Chung
158a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionLeft() {
159e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.left;
160a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
161a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
162a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionTop() {
163e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.top;
164a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
165a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
166a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionWidth() {
167e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.width();
168a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
169a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
170a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    public int getDragRegionHeight() {
171e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion.height();
172e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
173e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
174b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    public void setDragVisualizeOffset(Point p) {
175b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragVisualizeOffset = p;
176b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    }
177b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung
178b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    public Point getDragVisualizeOffset() {
179b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        return mDragVisualizeOffset;
180b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung    }
181b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung
182e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    public void setDragRegion(Rect r) {
183e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        mDragRegion = r;
184e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
185e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
186e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    public Rect getDragRegion() {
187e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return mDragRegion;
188a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
189a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
19000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    @Override
19100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
192eebd92496e2fbfbd81ea871862a681929101ba06Joe Onorato        setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
19300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
19400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
195d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    // Draws drag shadow for system DND.
19642e28092b336bf89bee94c61e2cd327e1d8ec882Sunny Goyal    @SuppressLint("WrongCall")
197d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    public void drawDragShadow(Canvas canvas) {
198d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
199d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        canvas.scale(getScaleX(), getScaleY());
200d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        onDraw(canvas);
201d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        canvas.restoreToCount(saveCount);
202d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    }
203d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
204d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    // Provides drag shadow metrics for system DND.
205d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    public void provideDragShadowMetrics(Point size, Point touch) {
206d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev        size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
207d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
20837bd006b73b4399ba10bb46e7f57a56b2e133e86Vadim Tryshev        final float xGrowth = mBitmap.getWidth() * (getScaleX() - 1);
20937bd006b73b4399ba10bb46e7f57a56b2e133e86Vadim Tryshev        final float yGrowth = mBitmap.getHeight() * (getScaleY() - 1);
2109430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev        touch.set(
2119430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev                mRegistrationX + (int)Math.round(xGrowth / 2),
2129430ff23c8a1127341e73b285e901a5cb9f1b5f7Vadim Tryshev                mRegistrationY + (int)Math.round(yGrowth / 2));
213d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev    }
214d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev
21500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    @Override
21600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    protected void onDraw(Canvas canvas) {
217fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        mHasDrawn = true;
218ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
219ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        if (crossFade) {
220ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
221ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            mPaint.setAlpha(alpha);
222ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
22300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
224ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        if (crossFade) {
225ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            mPaint.setAlpha((int) (255 * mCrossFadeProgress));
226d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
227ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
228ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
229ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            canvas.scale(sX, sY);
230ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
231d6c8e7eeb13094ea1349897663ae28d8a3bf2773Vadim Tryshev            canvas.restoreToCount(saveCount);
232ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        }
233ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
234ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
235ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
236ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        mCrossFadeBitmap = crossFadeBitmap;
237ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    }
238ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen
239ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen    public void crossFade(int duration) {
240cda3bfb2e1d89ad872558dd0a82ae79ca6fe41eaJon Miranda        ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
241ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.setDuration(duration);
242ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.setInterpolator(new DecelerateInterpolator(1.5f));
243ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.addUpdateListener(new AnimatorUpdateListener() {
244ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            @Override
245ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            public void onAnimationUpdate(ValueAnimator animation) {
246ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen                mCrossFadeProgress = animation.getAnimatedFraction();
2475d2fc32e6da66f877dfba4fe513fbabdcdae5f99Sunny Goyal                invalidate();
248ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen            }
249ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        });
250ed66b2bac7447febe2e405b4ce725cae4f6b5988Adam Cohen        va.start();
25100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
25200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
25361967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung    public void setColor(int color) {
2546cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        if (mPaint == null) {
2556cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka            mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
2566cfafb96c3b108fec90897c1a251229be9861ddbMichael Jurka        }
25761967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        if (color != 0) {
258fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            ColorMatrix m1 = new ColorMatrix();
259fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            m1.setSaturation(0);
260fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
261fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            ColorMatrix m2 = new ColorMatrix();
2626c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickham            Themes.setColorScaleOnMatrix(color, m2);
263fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            m1.postConcat(m2);
264fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
265a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal            animateFilterTo(m1.getArray());
26661967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        } else {
267a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal            if (mCurrentFilter == null) {
268fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                mPaint.setColorFilter(null);
269fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                invalidate();
270fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            } else {
271fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                animateFilterTo(new ColorMatrix().getArray());
272fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            }
27361967cb17f8fa9ee01f93e9f25a1074559b54cf3Winson Chung        }
274fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    }
275fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
276fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal    private void animateFilterTo(float[] targetFilter) {
277fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
278fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
279fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
280fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        if (mFilterAnimator != null) {
281fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            mFilterAnimator.cancel();
282fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        }
283fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
284fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                oldFilter, targetFilter);
285fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
286fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
287fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal
288fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            @Override
289fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            public void onAnimationUpdate(ValueAnimator animation) {
290fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
291fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal                invalidate();
292fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal            }
293fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        });
294fe0d1f2458e6a442613b070ae549124a4780e759Sunny Goyal        mFilterAnimator.start();
29500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
29600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
297fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    public boolean hasDrawn() {
298fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen        return mHasDrawn;
299fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen    }
300fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
3013e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    @Override
3023e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public void setAlpha(float alpha) {
3033e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        super.setAlpha(alpha);
3043e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        mPaint.setAlpha((int) (255 * alpha));
3053e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        invalidate();
3063e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    }
3073e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
30800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
30900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Create a window containing this view and show it.
31000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
3118dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchX the x coordinate the user touched in DragLayer coordinates
3128dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchY the y coordinate the user touched in DragLayer coordinates
31300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
3148dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen    public void show(int touchX, int touchY) {
3158dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        mDragLayer.addView(this);
316043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung
317043f2af567178b82b0b41f12d379e7dd12da2936Winson Chung        // Start the pick-up animation
3188dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
3198dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.width = mBitmap.getWidth();
3208dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.height = mBitmap.getHeight();
3218dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        lp.customPosition = true;
3228dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen        setLayoutParams(lp);
323a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        move(touchX, touchY);
324ca99383daef92fed673de22126875cb485be494fMichael Jurka        // Post the animation to skip other expensive work happening on the first frame
325ca99383daef92fed673de22126875cb485be494fMichael Jurka        post(new Runnable() {
326a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham            public void run() {
327a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham                mAnim.start();
328a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham            }
329a501d49a6a8b684bc83aa6b536f43247d75bacdfTony Wickham        });
33000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
331716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
3327bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    public void cancelAnimation() {
333456e87e1943ee4e779929f77a9cf11de7af3ec6aVadim Tryshev        mAnimationCancelled = true;
3347bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (mAnim != null && mAnim.isRunning()) {
3357bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mAnim.cancel();
3367bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
3377bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung    }
3387bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung
33900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    /**
34000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     * Move the window containing this view.
34100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     *
3428dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchX the x coordinate the user touched in DragLayer coordinates
3438dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen     * @param touchY the y coordinate the user touched in DragLayer coordinates
34400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
3451bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public void move(int touchX, int touchY) {
346a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mLastTouchX = touchX;
347a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mLastTouchY = touchY;
348a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        applyTranslation();
349a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
350a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
351ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham    public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
352ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham        mTempLoc[0] = toTouchX - mRegistrationX;
353ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham        mTempLoc[1] = toTouchY - mRegistrationY;
354ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham        mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mInitialScale, mInitialScale,
355ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham                DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
356ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham    }
357ea62fe0be19c54f8fbb434c6334418b96626f70dTony Wickham
358a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    public void animateShift(final int shiftX, final int shiftY) {
359a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        if (mAnim.isStarted()) {
360a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            return;
361a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        }
362a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mAnimatedShiftX = shiftX;
363a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mAnimatedShiftY = shiftY;
364a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        applyTranslation();
365a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        mAnim.addUpdateListener(new AnimatorUpdateListener() {
366a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            @Override
367a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            public void onAnimationUpdate(ValueAnimator animation) {
368a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                float fraction = 1 - animation.getAnimatedFraction();
369a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                mAnimatedShiftX = (int) (fraction * shiftX);
370a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                mAnimatedShiftY = (int) (fraction * shiftY);
371a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal                applyTranslation();
372a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal            }
373a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        });
374a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    }
375a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal
376a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal    private void applyTranslation() {
377a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        setTranslationX(mLastTouchX - mRegistrationX + mAnimatedShiftX);
378a2454ad2d8dcffa94f670853eb464726c73597f1Sunny Goyal        setTranslationY(mLastTouchY - mRegistrationY + mAnimatedShiftY);
37900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    }
38000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
3811bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham    public void remove() {
3827bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        if (getParent() != null) {
3837bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung            mDragLayer.removeView(DragView.this);
3847bd1bbb509f9569fa18d6b4d33242679fd98bc9bWinson Chung        }
3856f13342ffd3f968de9ff86b988621cc91d94adffPatrick Dubroy    }
3863a644ed1ce12554fcdf5c499e959bda986d10551Sunny Goyal
387c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda    public int getBlurSizeOutline() {
388c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda        return mBlurSizeOutline;
389c9c57631a985a8e1a4eac17ef0952bd344e281a2Jon Miranda    }
390dec3a908bfa395095e80e4a532cff98612b624deSunny Goyal
391dec3a908bfa395095e80e4a532cff98612b624deSunny Goyal    public float getInitialScale() {
392dec3a908bfa395095e80e4a532cff98612b624deSunny Goyal        return mInitialScale;
393dec3a908bfa395095e80e4a532cff98612b624deSunny Goyal    }
39400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato}
395