blob: b02e22b16bff033c0386c4444db971cda5df3a20 [file] [log] [blame]
/*
* 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.launcher2;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.animation.DecelerateInterpolator;
import com.android.launcher.R;
public class DragView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private int mRegistrationX;
private int mRegistrationY;
private Rect mDragRegion = null;
ValueAnimator mAnim;
private float mOffsetX = 0.0f;
private float mOffsetY = 0.0f;
private WindowManager.LayoutParams mLayoutParams;
private WindowManager mWindowManager;
/**
* A callback to be called the first time this view is drawn.
* This allows the originator of the drag to dim or hide the original view as soon
* as the DragView is drawn.
*/
private Runnable mOnDrawRunnable = null;
/**
* Construct the drag view.
* <p>
* The registration point is the point inside our view that the touch events should
* be centered upon.
*
* @param context A context
* @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.
*/
public DragView(Context context, Bitmap bitmap, int registrationX, int registrationY,
int left, int top, int width, int height) {
super(context);
final Resources res = getResources();
final int dragScale = res.getInteger(R.integer.config_dragViewExtraPixels);
mWindowManager = WindowManagerImpl.getDefault();
Matrix scale = new Matrix();
final float scaleFactor = (width + dragScale) / width;
if (scaleFactor != 1.0f) {
scale.setScale(scaleFactor, scaleFactor);
}
final int offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
final int offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
// Animate the view into the correct position
mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
mAnim.setDuration(110);
mAnim.setInterpolator(new DecelerateInterpolator(2.5f));
mAnim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final float value = (Float) animation.getAnimatedValue();
final int deltaX = (int) ((value * offsetX) - mOffsetX);
final int deltaY = (int) ((value * offsetY) - mOffsetY);
mOffsetX += deltaX;
mOffsetY += deltaY;
if (getParent() == null) {
animation.cancel();
} else {
WindowManager.LayoutParams lp = mLayoutParams;
lp.x += deltaX;
lp.y += deltaY;
mWindowManager.updateViewLayout(DragView.this, lp);
}
}
});
mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
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);
}
public float getOffsetY() {
return mOffsetY;
}
public void setOnDrawRunnable(Runnable r) {
mOnDrawRunnable = r;
}
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 setDragRegion(Rect r) {
mDragRegion = r;
}
public Rect getDragRegion() {
return mDragRegion;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
if (false) {
// for debugging
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(0xaaffffff);
canvas.drawRect(0, 0, getWidth(), getHeight(), p);
}
// Call the callback if we haven't already been detached
if (getParent() != null) {
if (mOnDrawRunnable != null) {
mOnDrawRunnable.run();
mOnDrawRunnable = null;
}
}
canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mBitmap.recycle();
}
public void setPaint(Paint paint) {
mPaint = paint;
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 screen coordinates
* @param touchY the y coordinate the user touched in screen coordinates
*/
public void show(IBinder windowToken, int touchX, int touchY) {
WindowManager.LayoutParams lp;
int pixelFormat;
pixelFormat = PixelFormat.TRANSLUCENT;
lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
touchX - mRegistrationX, touchY - mRegistrationY,
WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
/*| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM*/,
pixelFormat);
// lp.token = mStatusBarView.getWindowToken();
lp.gravity = Gravity.LEFT | Gravity.TOP;
lp.token = windowToken;
lp.setTitle("DragView");
mLayoutParams = lp;
mWindowManager.addView(this, lp);
mAnim.start();
}
/**
* Move the window containing this view.
*
* @param touchX the x coordinate the user touched in screen coordinates
* @param touchY the y coordinate the user touched in screen coordinates
*/
void move(int touchX, int touchY) {
WindowManager.LayoutParams lp = mLayoutParams;
lp.x = touchX - mRegistrationX + (int) mOffsetX;
lp.y = touchY - mRegistrationY + (int) mOffsetY;
mWindowManager.updateViewLayout(this, lp);
}
void remove() {
mWindowManager.removeView(this);
}
int[] getPosition(int[] result) {
WindowManager.LayoutParams lp = mLayoutParams;
if (result == null) result = new int[2];
result[0] = lp.x;
result[1] = lp.y;
return result;
}
}