1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package com.android.launcher2;
19
20import android.animation.ValueAnimator;
21import android.animation.ValueAnimator.AnimatorUpdateListener;
22import android.content.res.Resources;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25import android.graphics.Matrix;
26import android.graphics.Paint;
27import android.graphics.Point;
28import android.graphics.Rect;
29import android.view.View;
30import android.view.animation.DecelerateInterpolator;
31
32import com.android.launcher.R;
33
34public class DragView extends View {
35    private Bitmap mBitmap;
36    private Paint mPaint;
37    private int mRegistrationX;
38    private int mRegistrationY;
39
40    private Point mDragVisualizeOffset = null;
41    private Rect mDragRegion = null;
42    private DragLayer mDragLayer = null;
43    private boolean mHasDrawn = false;
44
45    ValueAnimator mAnim;
46    private float mOffsetX = 0.0f;
47    private float mOffsetY = 0.0f;
48
49    private DragLayer.LayoutParams mLayoutParams;
50
51    /**
52     * Construct the drag view.
53     * <p>
54     * The registration point is the point inside our view that the touch events should
55     * be centered upon.
56     *
57     * @param launcher The Launcher instance
58     * @param bitmap The view that we're dragging around.  We scale it up when we draw it.
59     * @param registrationX The x coordinate of the registration point.
60     * @param registrationY The y coordinate of the registration point.
61     */
62    public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
63            int left, int top, int width, int height) {
64        super(launcher);
65        mDragLayer = launcher.getDragLayer();
66
67        final Resources res = getResources();
68        final int dragScale = res.getInteger(R.integer.config_dragViewExtraPixels);
69
70        Matrix scale = new Matrix();
71        final float scaleFactor = (width + dragScale) / width;
72        if (scaleFactor != 1.0f) {
73            scale.setScale(scaleFactor, scaleFactor);
74        }
75
76        final int offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
77        final int offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
78
79        // Animate the view into the correct position
80        mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
81        mAnim.setDuration(110);
82        mAnim.setInterpolator(new DecelerateInterpolator(2.5f));
83        mAnim.addUpdateListener(new AnimatorUpdateListener() {
84            @Override
85            public void onAnimationUpdate(ValueAnimator animation) {
86                final float value = (Float) animation.getAnimatedValue();
87
88                final int deltaX = (int) ((value * offsetX) - mOffsetX);
89                final int deltaY = (int) ((value * offsetY) - mOffsetY);
90
91                mOffsetX += deltaX;
92                mOffsetY += deltaY;
93
94                if (getParent() == null) {
95                    animation.cancel();
96                } else {
97                    DragLayer.LayoutParams lp = mLayoutParams;
98                    lp.x += deltaX;
99                    lp.y += deltaY;
100                    mDragLayer.requestLayout();
101                }
102            }
103        });
104
105        mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
106        setDragRegion(new Rect(0, 0, width, height));
107
108        // The point in our scaled bitmap that the touch events are located
109        mRegistrationX = registrationX;
110        mRegistrationY = registrationY;
111
112        // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
113        int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
114        measure(ms, ms);
115    }
116
117    public float getOffsetY() {
118        return mOffsetY;
119    }
120
121    public int getDragRegionLeft() {
122        return mDragRegion.left;
123    }
124
125    public int getDragRegionTop() {
126        return mDragRegion.top;
127    }
128
129    public int getDragRegionWidth() {
130        return mDragRegion.width();
131    }
132
133    public int getDragRegionHeight() {
134        return mDragRegion.height();
135    }
136
137    public void setDragVisualizeOffset(Point p) {
138        mDragVisualizeOffset = p;
139    }
140
141    public Point getDragVisualizeOffset() {
142        return mDragVisualizeOffset;
143    }
144
145    public void setDragRegion(Rect r) {
146        mDragRegion = r;
147    }
148
149    public Rect getDragRegion() {
150        return mDragRegion;
151    }
152
153    @Override
154    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
155        setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
156    }
157
158    @Override
159    protected void onDraw(Canvas canvas) {
160        if (false) {
161            // for debugging
162            Paint p = new Paint();
163            p.setStyle(Paint.Style.FILL);
164            p.setColor(0xaaffffff);
165            canvas.drawRect(0, 0, getWidth(), getHeight(), p);
166        }
167
168        mHasDrawn = true;
169        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
170    }
171
172    public void setPaint(Paint paint) {
173        mPaint = paint;
174        invalidate();
175    }
176
177    public boolean hasDrawn() {
178        return mHasDrawn;
179    }
180
181    @Override
182    public void setAlpha(float alpha) {
183        super.setAlpha(alpha);
184        if (mPaint == null) {
185            mPaint = new Paint();
186        }
187        mPaint.setAlpha((int) (255 * alpha));
188        invalidate();
189    }
190
191    /**
192     * Create a window containing this view and show it.
193     *
194     * @param windowToken obtained from v.getWindowToken() from one of your views
195     * @param touchX the x coordinate the user touched in DragLayer coordinates
196     * @param touchY the y coordinate the user touched in DragLayer coordinates
197     */
198    public void show(int touchX, int touchY) {
199        mDragLayer.addView(this);
200        DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
201        lp.width = mBitmap.getWidth();
202        lp.height = mBitmap.getHeight();
203        lp.x = touchX - mRegistrationX;
204        lp.y = touchY - mRegistrationY;
205        lp.customPosition = true;
206        setLayoutParams(lp);
207        mLayoutParams = lp;
208        mAnim.start();
209    }
210
211    /**
212     * Move the window containing this view.
213     *
214     * @param touchX the x coordinate the user touched in DragLayer coordinates
215     * @param touchY the y coordinate the user touched in DragLayer coordinates
216     */
217    void move(int touchX, int touchY) {
218        DragLayer.LayoutParams lp = mLayoutParams;
219        lp.x = touchX - mRegistrationX + (int) mOffsetX;
220        lp.y = touchY - mRegistrationY + (int) mOffsetY;
221        mDragLayer.requestLayout();
222    }
223
224    void remove() {
225        post(new Runnable() {
226            public void run() {
227                mDragLayer.removeView(DragView.this);
228            }
229        });
230    }
231
232    int[] getPosition(int[] result) {
233        DragLayer.LayoutParams lp = mLayoutParams;
234        if (result == null) result = new int[2];
235        result[0] = lp.x;
236        result[1] = lp.y;
237        return result;
238    }
239}
240
241