summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/dragndrop/DragView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/dragndrop/DragView.java')
-rw-r--r--src/com/android/launcher3/dragndrop/DragView.java366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
new file mode 100644
index 000000000..88e11fa61
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dragndrop;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Build;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Thunk;
+
+import com.android.launcher3.R;
+
+import java.util.Arrays;
+
+public class DragView extends View {
+ public static int COLOR_CHANGE_DURATION = 120;
+
+ @Thunk static float sDragAlpha = 1f;
+
+ private Bitmap mBitmap;
+ private Bitmap mCrossFadeBitmap;
+ @Thunk Paint mPaint;
+ private final int mRegistrationX;
+ private final int mRegistrationY;
+
+ private Point mDragVisualizeOffset = null;
+ private Rect mDragRegion = null;
+ private final DragLayer mDragLayer;
+ @Thunk final DragController mDragController;
+ private boolean mHasDrawn = false;
+ @Thunk float mCrossFadeProgress = 0f;
+ private boolean mAnimationCancelled = false;
+
+ ValueAnimator mAnim;
+ // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
+ // size. This is ignored for non-icons.
+ private float mIntrinsicIconScale = 1f;
+
+ @Thunk float[] mCurrentFilter;
+ private ValueAnimator mFilterAnimator;
+
+ /**
+ * Construct the drag view.
+ * <p>
+ * The registration point is the point inside our view that the touch events should
+ * be centered upon.
+ *
+ * @param launcher The Launcher instance
+ * @param bitmap The view that we're dragging around. We scale it up when we draw it.
+ * @param registrationX The x coordinate of the registration point.
+ * @param registrationY The y coordinate of the registration point.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
+ int left, int top, int width, int height, final float initialScale) {
+ super(launcher);
+ mDragLayer = launcher.getDragLayer();
+ mDragController = launcher.getDragController();
+
+ final Resources res = getResources();
+ final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale);
+ final float scale = (width + scaleDps) / width;
+
+ // Set the initial scale to avoid any jumps
+ setScaleX(initialScale);
+ setScaleY(initialScale);
+
+ // Animate the view into the correct position
+ mAnim = LauncherAnimUtils.ofFloat(this, 0f, 1f);
+ mAnim.setDuration(150);
+ mAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float value = (Float) animation.getAnimatedValue();
+
+ setScaleX(initialScale + (value * (scale - initialScale)));
+ setScaleY(initialScale + (value * (scale - initialScale)));
+ if (sDragAlpha != 1f) {
+ setAlpha(sDragAlpha * value + (1f - value));
+ }
+
+ if (getParent() == null) {
+ animation.cancel();
+ }
+ }
+ });
+
+ mAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mAnimationCancelled) {
+ mDragController.onDragViewAnimationEnd();
+ }
+ }
+ });
+
+ mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height);
+ setDragRegion(new Rect(0, 0, width, height));
+
+ // The point in our scaled bitmap that the touch events are located
+ mRegistrationX = registrationX;
+ mRegistrationY = registrationY;
+
+ // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
+ int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ measure(ms, ms);
+ mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+ if (Utilities.ATLEAST_LOLLIPOP) {
+ setElevation(getResources().getDimension(R.dimen.drag_elevation));
+ }
+ }
+
+ /** Sets the scale of the view over the normal workspace icon size. */
+ public void setIntrinsicIconScaleFactor(float scale) {
+ mIntrinsicIconScale = scale;
+ }
+
+ public float getIntrinsicIconScaleFactor() {
+ return mIntrinsicIconScale;
+ }
+
+ public int getDragRegionLeft() {
+ return mDragRegion.left;
+ }
+
+ public int getDragRegionTop() {
+ return mDragRegion.top;
+ }
+
+ public int getDragRegionWidth() {
+ return mDragRegion.width();
+ }
+
+ public int getDragRegionHeight() {
+ return mDragRegion.height();
+ }
+
+ public void setDragVisualizeOffset(Point p) {
+ mDragVisualizeOffset = p;
+ }
+
+ public Point getDragVisualizeOffset() {
+ return mDragVisualizeOffset;
+ }
+
+ public void setDragRegion(Rect r) {
+ mDragRegion = r;
+ }
+
+ public Rect getDragRegion() {
+ return mDragRegion;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
+ }
+
+ // Draws drag shadow for system DND.
+ @SuppressLint("WrongCall")
+ public void drawDragShadow(Canvas canvas) {
+ final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.scale(getScaleX(), getScaleY());
+ onDraw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+
+ // Provides drag shadow metrics for system DND.
+ public void provideDragShadowMetrics(Point size, Point touch) {
+ size.set((int)(mBitmap.getWidth() * getScaleX()), (int)(mBitmap.getHeight() * getScaleY()));
+
+ final float xGrowth = mBitmap.getWidth() * (getScaleX() - 1);
+ final float yGrowth = mBitmap.getHeight() * (getScaleY() - 1);
+ touch.set(
+ mRegistrationX + (int)Math.round(xGrowth / 2),
+ mRegistrationY + (int)Math.round(yGrowth / 2));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mHasDrawn = true;
+ boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
+ if (crossFade) {
+ int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255;
+ mPaint.setAlpha(alpha);
+ }
+ canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+ if (crossFade) {
+ mPaint.setAlpha((int) (255 * mCrossFadeProgress));
+ final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
+ float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
+ canvas.scale(sX, sY);
+ canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
+ canvas.restoreToCount(saveCount);
+ }
+ }
+
+ public void setCrossFadeBitmap(Bitmap crossFadeBitmap) {
+ mCrossFadeBitmap = crossFadeBitmap;
+ }
+
+ public void crossFade(int duration) {
+ ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1f);
+ va.setDuration(duration);
+ va.setInterpolator(new DecelerateInterpolator(1.5f));
+ va.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mCrossFadeProgress = animation.getAnimatedFraction();
+ invalidate();
+ }
+ });
+ va.start();
+ }
+
+ public void setColor(int color) {
+ if (mPaint == null) {
+ mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+ }
+ if (color != 0) {
+ ColorMatrix m1 = new ColorMatrix();
+ m1.setSaturation(0);
+
+ ColorMatrix m2 = new ColorMatrix();
+ setColorScale(color, m2);
+ m1.postConcat(m2);
+
+ if (Utilities.ATLEAST_LOLLIPOP) {
+ animateFilterTo(m1.getArray());
+ } else {
+ mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
+ invalidate();
+ }
+ } else {
+ if (!Utilities.ATLEAST_LOLLIPOP || mCurrentFilter == null) {
+ mPaint.setColorFilter(null);
+ invalidate();
+ } else {
+ animateFilterTo(new ColorMatrix().getArray());
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void animateFilterTo(float[] targetFilter) {
+ float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
+ mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
+
+ if (mFilterAnimator != null) {
+ mFilterAnimator.cancel();
+ }
+ mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
+ oldFilter, targetFilter);
+ mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
+ mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+ invalidate();
+ }
+ });
+ mFilterAnimator.start();
+ }
+
+ public boolean hasDrawn() {
+ return mHasDrawn;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ mPaint.setAlpha((int) (255 * alpha));
+ invalidate();
+ }
+
+ /**
+ * Create a window containing this view and show it.
+ *
+ * @param windowToken obtained from v.getWindowToken() from one of your views
+ * @param touchX the x coordinate the user touched in DragLayer coordinates
+ * @param touchY the y coordinate the user touched in DragLayer coordinates
+ */
+ public void show(int touchX, int touchY) {
+ mDragLayer.addView(this);
+
+ // Start the pick-up animation
+ DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
+ lp.width = mBitmap.getWidth();
+ lp.height = mBitmap.getHeight();
+ lp.customPosition = true;
+ setLayoutParams(lp);
+ setTranslationX(touchX - mRegistrationX);
+ setTranslationY(touchY - mRegistrationY);
+ // Post the animation to skip other expensive work happening on the first frame
+ post(new Runnable() {
+ public void run() {
+ mAnim.start();
+ }
+ });
+ }
+
+ public void cancelAnimation() {
+ mAnimationCancelled = true;
+ if (mAnim != null && mAnim.isRunning()) {
+ mAnim.cancel();
+ }
+ }
+
+ /**
+ * Move the window containing this view.
+ *
+ * @param touchX the x coordinate the user touched in DragLayer coordinates
+ * @param touchY the y coordinate the user touched in DragLayer coordinates
+ */
+ void move(int touchX, int touchY) {
+ setTranslationX(touchX - mRegistrationX);
+ setTranslationY(touchY - mRegistrationY);
+ }
+
+ void remove() {
+ if (getParent() != null) {
+ mDragLayer.removeView(DragView.this);
+ }
+ }
+
+ public static void setColorScale(int color, ColorMatrix target) {
+ target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+ Color.blue(color) / 255f, Color.alpha(color) / 255f);
+ }
+}