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         // Set the initial scale to avoid any jumps
     79         setScaleX(initialScale);
     80         setScaleY(initialScale);
     81 
     82         // Animate the view into the correct position
     83         mAnim = LauncherAnimUtils.ofFloat(0.0f, 1.0f);
     84         mAnim.setDuration(150);
     85         mAnim.addUpdateListener(new AnimatorUpdateListener() {
     86             @Override
     87             public void onAnimationUpdate(ValueAnimator animation) {
     88                 final float value = (Float) animation.getAnimatedValue();
     89 
     90                 final int deltaX = (int) ((value * offsetX) - mOffsetX);
     91                 final int deltaY = (int) ((value * offsetY) - mOffsetY);
     92 
     93                 mOffsetX += deltaX;
     94                 mOffsetY += deltaY;
     95                 setScaleX(initialScale + (value * (scale - initialScale)));
     96                 setScaleY(initialScale + (value * (scale - initialScale)));
     97                 if (sDragAlpha != 1f) {
     98                     setAlpha(sDragAlpha * value + (1f - value));
     99                 }
    100 
    101                 if (getParent() == null) {
    102                     animation.cancel();
    103                 } else {
    104                     setTranslationX(getTranslationX() + deltaX);
    105                     setTranslationY(getTranslationY() + deltaY);
    106                 }
    107             }
    108         });
    109 
    110         mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
    111         setDragRegion(new Rect(0, 0, width, height));
    112 
    113         // The point in our scaled bitmap that the touch events are located
    114         mRegistrationX = registrationX;
    115         mRegistrationY = registrationY;
    116 
    117         // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
    118         int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    119         measure(ms, ms);
    120         mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
    121     }
    122 
    123     public float getOffsetY() {
    124         return mOffsetY;
    125     }
    126 
    127     public int getDragRegionLeft() {
    128         return mDragRegion.left;
    129     }
    130 
    131     public int getDragRegionTop() {
    132         return mDragRegion.top;
    133     }
    134 
    135     public int getDragRegionWidth() {
    136         return mDragRegion.width();
    137     }
    138 
    139     public int getDragRegionHeight() {
    140         return mDragRegion.height();
    141     }
    142 
    143     public void setDragVisualizeOffset(Point p) {
    144         mDragVisualizeOffset = p;
    145     }
    146 
    147     public Point getDragVisualizeOffset() {
    148         return mDragVisualizeOffset;
    149     }
    150 
    151     public void setDragRegion(Rect r) {
    152         mDragRegion = r;
    153     }
    154 
    155     public Rect getDragRegion() {
    156         return mDragRegion;
    157     }
    158 
    159     public float getInitialScale() {
    160         return mInitialScale;
    161     }
    162 
    163     public void updateInitialScaleToCurrentScale() {
    164         mInitialScale = getScaleX();
    165     }
    166 
    167     @Override
    168     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    169         setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
    170     }
    171 
    172     @Override
    173     protected void onDraw(Canvas canvas) {
    174         @SuppressWarnings("all") // suppress dead code warning
    175         final boolean debug = false;
    176         if (debug) {
    177             Paint p = new Paint();
    178             p.setStyle(Paint.Style.FILL);
    179             p.setColor(0x66ffffff);
    180             canvas.drawRect(0, 0, getWidth(), getHeight(), p);
    181         }
    182 
    183         mHasDrawn = true;
    184         boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
    185         if (crossFade) {
    186             int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
    187             mPaint.setAlpha(alpha);
    188         }
    189         canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
    190         if (crossFade) {
    191             mPaint.setAlpha((int) (255 * mCrossFadeProgress));
    192             canvas.save();
    193             float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
    194             float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
    195             canvas.scale(sX, sY);
    196             canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
    197             canvas.restore();
    198         }
    199     }
    200 
    201     public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
    202         mCrossFadeBitmap = crossFadeBitmap;
    203     }
    204 
    205     public void crossFade(int duration) {
    206         ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
    207         va.setDuration(duration);
    208         va.setInterpolator(new DecelerateInterpolator(1.5f));
    209         va.addUpdateListener(new AnimatorUpdateListener() {
    210             @Override
    211             public void onAnimationUpdate(ValueAnimator animation) {
    212                 mCrossFadeProgress = animation.getAnimatedFraction();
    213             }
    214         });
    215         va.start();
    216     }
    217 
    218     public void setColor(int color) {
    219         if (mPaint == null) {
    220             mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
    221         }
    222         if (color != 0) {
    223             mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
    224         } else {
    225             mPaint.setColorFilter(null);
    226         }
    227         invalidate();
    228     }
    229 
    230     public boolean hasDrawn() {
    231         return mHasDrawn;
    232     }
    233 
    234     @Override
    235     public void setAlpha(float alpha) {
    236         super.setAlpha(alpha);
    237         mPaint.setAlpha((int) (255 * alpha));
    238         invalidate();
    239     }
    240 
    241     /**
    242      * Create a window containing this view and show it.
    243      *
    244      * @param windowToken obtained from v.getWindowToken() from one of your views
    245      * @param touchX the x coordinate the user touched in DragLayer coordinates
    246      * @param touchY the y coordinate the user touched in DragLayer coordinates
    247      */
    248     public void show(int touchX, int touchY) {
    249         mDragLayer.addView(this);
    250 
    251         // Start the pick-up animation
    252         DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
    253         lp.width = mBitmap.getWidth();
    254         lp.height = mBitmap.getHeight();
    255         lp.customPosition = true;
    256         setLayoutParams(lp);
    257         setTranslationX(touchX - mRegistrationX);
    258         setTranslationY(touchY - mRegistrationY);
    259         // Post the animation to skip other expensive work happening on the first frame
    260         post(new Runnable() {
    261                 public void run() {
    262                     mAnim.start();
    263                 }
    264             });
    265     }
    266 
    267     public void cancelAnimation() {
    268         if (mAnim != null && mAnim.isRunning()) {
    269             mAnim.cancel();
    270         }
    271     }
    272 
    273     public void resetLayoutParams() {
    274         mOffsetX = mOffsetY = 0;
    275         requestLayout();
    276     }
    277 
    278     /**
    279      * Move the window containing this view.
    280      *
    281      * @param touchX the x coordinate the user touched in DragLayer coordinates
    282      * @param touchY the y coordinate the user touched in DragLayer coordinates
    283      */
    284     void move(int touchX, int touchY) {
    285         setTranslationX(touchX - mRegistrationX + (int) mOffsetX);
    286         setTranslationY(touchY - mRegistrationY + (int) mOffsetY);
    287     }
    288 
    289     void remove() {
    290         if (getParent() != null) {
    291             mDragLayer.removeView(DragView.this);
    292         }
    293     }
    294 }
    295 
    296