Home | History | Annotate | Download | only in launcher2
      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 
     18 package com.android.launcher2;
     19 
     20 import android.animation.ValueAnimator;
     21 import android.animation.ValueAnimator.AnimatorUpdateListener;
     22 import android.content.res.Resources;
     23 import android.graphics.Bitmap;
     24 import android.graphics.Canvas;
     25 import android.graphics.Paint;
     26 import android.graphics.Point;
     27 import android.graphics.PorterDuff;
     28 import android.graphics.PorterDuffColorFilter;
     29 import android.graphics.Rect;
     30 import android.view.View;
     31 import android.view.animation.DecelerateInterpolator;
     32 
     33 import com.android.launcher.R;
     34 
     35 public class DragView extends View {
     36     private static float sDragAlpha = 1f;
     37 
     38     private Bitmap mBitmap;
     39     private Bitmap mCrossFadeBitmap;
     40     private Paint mPaint;
     41     private int mRegistrationX;
     42     private int mRegistrationY;
     43 
     44     private Point mDragVisualizeOffset = null;
     45     private Rect mDragRegion = null;
     46     private DragLayer mDragLayer = null;
     47     private boolean mHasDrawn = false;
     48     private float mCrossFadeProgress = 0f;
     49 
     50     ValueAnimator mAnim;
     51     private float mOffsetX = 0.0f;
     52     private float mOffsetY = 0.0f;
     53     private float mInitialScale = 1f;
     54 
     55     /**
     56      * Construct the drag view.
     57      * <p>
     58      * The registration point is the point inside our view that the touch events should
     59      * be centered upon.
     60      *
     61      * @param launcher The Launcher instance
     62      * @param bitmap The view that we're dragging around.  We scale it up when we draw it.
     63      * @param registrationX The x coordinate of the registration point.
     64      * @param registrationY The y coordinate of the registration point.
     65      */
     66     public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
     67             int left, int top, int width, int height, final float initialScale) {
     68         super(launcher);
     69         mDragLayer = launcher.getDragLayer();
     70         mInitialScale = initialScale;
     71 
     72         final Resources res = getResources();
     73         final float offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
     74         final float offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
     75         final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale);
     76         final float scale = (width + scaleDps) / width;
     77 
     78         // Animate the view into the correct position
     79         mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
     80         mAnim.setDuration(150);
     81         mAnim.addUpdateListener(new AnimatorUpdateListener() {
     82             @Override
     83             public void onAnimationUpdate(ValueAnimator animation) {
     84                 final float value = (Float) animation.getAnimatedValue();
     85 
     86                 final int deltaX = (int) ((value * offsetX) - mOffsetX);
     87                 final int deltaY = (int) ((value * offsetY) - mOffsetY);
     88 
     89                 mOffsetX += deltaX;
     90                 mOffsetY += deltaY;
     91                 setScaleX(initialScale + (value * (scale - initialScale)));
     92                 setScaleY(initialScale + (value * (scale - initialScale)));
     93                 if (sDragAlpha != 1f) {
     94                     setAlpha(sDragAlpha * value + (1f - value));
     95                 }
     96 
     97                 if (getParent() == null) {
     98                     animation.cancel();
     99                 } else {
    100                     setTranslationX(getTranslationX() + deltaX);
    101                     setTranslationY(getTranslationY() + deltaY);
    102                 }
    103             }
    104         });
    105 
    106         mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
    107         setDragRegion(new Rect(0, 0, width, height));
    108 
    109         // The point in our scaled bitmap that the touch events are located
    110         mRegistrationX = registrationX;
    111         mRegistrationY = registrationY;
    112 
    113         // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
    114         int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    115         measure(ms, ms);
    116         mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
    117     }
    118 
    119     public float getOffsetY() {
    120         return mOffsetY;
    121     }
    122 
    123     public int getDragRegionLeft() {
    124         return mDragRegion.left;
    125     }
    126 
    127     public int getDragRegionTop() {
    128         return mDragRegion.top;
    129     }
    130 
    131     public int getDragRegionWidth() {
    132         return mDragRegion.width();
    133     }
    134 
    135     public int getDragRegionHeight() {
    136         return mDragRegion.height();
    137     }
    138 
    139     public void setDragVisualizeOffset(Point p) {
    140         mDragVisualizeOffset = p;
    141     }
    142 
    143     public Point getDragVisualizeOffset() {
    144         return mDragVisualizeOffset;
    145     }
    146 
    147     public void setDragRegion(Rect r) {
    148         mDragRegion = r;
    149     }
    150 
    151     public Rect getDragRegion() {
    152         return mDragRegion;
    153     }
    154 
    155     public float getInitialScale() {
    156         return mInitialScale;
    157     }
    158 
    159     public void updateInitialScaleToCurrentScale() {
    160         mInitialScale = getScaleX();
    161     }
    162 
    163     @Override
    164     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    165         setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
    166     }
    167 
    168     @Override
    169     protected void onDraw(Canvas canvas) {
    170         @SuppressWarnings("all") // suppress dead code warning
    171         final boolean debug = false;
    172         if (debug) {
    173             Paint p = new Paint();
    174             p.setStyle(Paint.Style.FILL);
    175             p.setColor(0x66ffffff);
    176             canvas.drawRect(0, 0, getWidth(), getHeight(), p);
    177         }
    178 
    179         mHasDrawn = true;
    180         boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
    181         if (crossFade) {
    182             int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
    183             mPaint.setAlpha(alpha);
    184         }
    185         canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
    186         if (crossFade) {
    187             mPaint.setAlpha((int) (255 * mCrossFadeProgress));
    188             canvas.save();
    189             float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
    190             float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
    191             canvas.scale(sX, sY);
    192             canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
    193             canvas.restore();
    194         }
    195     }
    196 
    197     public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
    198         mCrossFadeBitmap = crossFadeBitmap;
    199     }
    200 
    201     public void crossFade(int duration) {
    202         ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
    203         va.setDuration(duration);
    204         va.setInterpolator(new DecelerateInterpolator(1.5f));
    205         va.addUpdateListener(new AnimatorUpdateListener() {
    206             @Override
    207             public void onAnimationUpdate(ValueAnimator animation) {
    208                 mCrossFadeProgress = animation.getAnimatedFraction();
    209             }
    210         });
    211         va.start();
    212     }
    213 
    214     public void setColor(int color) {
    215         if (mPaint == null) {
    216             mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
    217         }
    218         if (color != 0) {
    219             mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
    220         } else {
    221             mPaint.setColorFilter(null);
    222         }
    223         invalidate();
    224     }
    225 
    226     public boolean hasDrawn() {
    227         return mHasDrawn;
    228     }
    229 
    230     @Override
    231     public void setAlpha(float alpha) {
    232         super.setAlpha(alpha);
    233         mPaint.setAlpha((int) (255 * alpha));
    234         invalidate();
    235     }
    236 
    237     /**
    238      * Create a window containing this view and show it.
    239      *
    240      * @param windowToken obtained from v.getWindowToken() from one of your views
    241      * @param touchX the x coordinate the user touched in DragLayer coordinates
    242      * @param touchY the y coordinate the user touched in DragLayer coordinates
    243      */
    244     public void show(int touchX, int touchY) {
    245         mDragLayer.addView(this);
    246 
    247         // Enable hw-layers on this view
    248         setLayerType(View.LAYER_TYPE_HARDWARE, null);
    249 
    250         // Start the pick-up animation
    251         DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
    252         lp.width = mBitmap.getWidth();
    253         lp.height = mBitmap.getHeight();
    254         lp.customPosition = true;
    255         setLayoutParams(lp);
    256         setTranslationX(touchX - mRegistrationX);
    257         setTranslationY(touchY - mRegistrationY);
    258         mAnim.start();
    259     }
    260 
    261     public void cancelAnimation() {
    262         if (mAnim != null && mAnim.isRunning()) {
    263             mAnim.cancel();
    264         }
    265     }
    266 
    267     public void resetLayoutParams() {
    268         mOffsetX = mOffsetY = 0;
    269         requestLayout();
    270     }
    271 
    272     /**
    273      * Move the window containing this view.
    274      *
    275      * @param touchX the x coordinate the user touched in DragLayer coordinates
    276      * @param touchY the y coordinate the user touched in DragLayer coordinates
    277      */
    278     void move(int touchX, int touchY) {
    279         setTranslationX(touchX - mRegistrationX + (int) mOffsetX);
    280         setTranslationY(touchY - mRegistrationY + (int) mOffsetY);
    281     }
    282 
    283     void remove() {
    284         if (getParent() != null) {
    285             // Disable hw-layers on this view
    286             setLayerType(View.LAYER_TYPE_NONE, null);
    287 
    288             mDragLayer.removeView(DragView.this);
    289         }
    290     }
    291 }
    292 
    293