summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/values-xlarge/config.xml7
-rw-r--r--src/com/android/launcher2/CellLayout.java100
-rw-r--r--src/com/android/launcher2/InterruptibleInOutAnimator.java69
3 files changed, 151 insertions, 25 deletions
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index f6f66461b..c7c68e22f 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -38,4 +38,11 @@
the drag view should be offset from the position of the original view. -->
<integer name="config_dragViewOffsetX">0</integer>
<integer name="config_dragViewOffsetY">12</integer>
+
+ <!-- The duration (in ms) of the fade animation on the object outlines, used when
+ we are dragging objects around on the home screen. -->
+ <integer name="config_dragOutlineFadeTime">900</integer>
+
+ <!-- The alpha value at which to show the most recent drop visualization outline. -->
+ <integer name="config_dragOutlineMaxAlpha">180</integer>
</resources>
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 08560e930..0f1d46998 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -31,13 +31,14 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.ContextMenu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.view.animation.LayoutAnimationController;
import java.util.Arrays;
@@ -79,15 +80,23 @@ public class CellLayout extends ViewGroup implements Dimmable {
private Drawable mBackground;
private Drawable mBackgroundMini;
private Drawable mBackgroundMiniHover;
- // If we're actively dragging something over this screen and it's small,
- // mHover is true
+ // If we're actively dragging something over this screen and it's small, mHover is true
private boolean mHover = false;
- private final RectF mDragRect = new RectF();
private final Point mDragCenter = new Point();
private Drawable mDragRectDrawable;
+ // These arrays are used to implement the drag visualization on x-large screens.
+ // They are used as circular arrays, indexed by mDragRectCurrent.
+ private Rect[] mDragRects = new Rect[8];
+ private int[] mDragRectAlphas = new int[mDragRects.length];
+ private InterruptibleInOutAnimator[] mDragRectAnims =
+ new InterruptibleInOutAnimator[mDragRects.length];
+
+ // Used as an index into the above 3 arrays; indicates which is the most current value.
+ private int mDragRectCurrent = 0;
+
private Drawable mCrosshairsDrawable = null;
private ValueAnimator mCrosshairsAnimator = null;
private float mCrosshairsVisibility = 0.0f;
@@ -139,15 +148,18 @@ public class CellLayout extends ViewGroup implements Dimmable {
if (LauncherApplication.isScreenXLarge()) {
final Resources res = getResources();
- mBackgroundMini = getResources().getDrawable(R.drawable.mini_home_screen_bg);
+ mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg);
mBackgroundMini.setFilterBitmap(true);
- mBackground = getResources().getDrawable(R.drawable.home_screen_bg);
+ mBackground = res.getDrawable(R.drawable.home_screen_bg);
mBackground.setFilterBitmap(true);
- mBackgroundMiniHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
+ mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
mBackgroundMiniHover.setFilterBitmap(true);
+ // Initialize the data structures used for the drag visualization.
+
mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
+ Interpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out
// Set up the animation for fading the crosshairs in and out
int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
@@ -158,6 +170,32 @@ public class CellLayout extends ViewGroup implements Dimmable {
CellLayout.this.invalidate();
}
});
+ mCrosshairsAnimator.setInterpolator(interp);
+
+ for (int i = 0; i < mDragRects.length; i++) {
+ mDragRects[i] = new Rect();
+ }
+
+ // When dragging things around the home screens, we show a green outline of
+ // where the item will land. The outlines gradually fade out, leaving a trail
+ // behind the drag path.
+ // Set up all the animations that are used to implement this fading.
+ final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
+ final int fromAlphaValue = 0;
+ final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
+ for (int i = 0; i < mDragRectAnims.length; i++) {
+ final InterruptibleInOutAnimator anim =
+ new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
+ anim.setInterpolator(interp);
+ final int thisIndex = i;
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
+ CellLayout.this.invalidate(mDragRects[thisIndex]);
+ }
+ });
+ mDragRectAnims[i] = anim;
+ }
}
}
@@ -200,16 +238,6 @@ public class CellLayout extends ViewGroup implements Dimmable {
final int countX = mCountX;
final int countY = mCountY;
- if (!mDragRect.isEmpty()) {
- mDragRectDrawable.setBounds(
- (int)mDragRect.left,
- (int)mDragRect.top,
- (int)mDragRect.right,
- (int)mDragRect.bottom);
- mDragRectDrawable.setAlpha((int) (mCrosshairsVisibility * 255));
- mDragRectDrawable.draw(canvas);
- }
-
final float MAX_ALPHA = 0.4f;
final int MAX_VISIBLE_DISTANCE = 600;
final float DISTANCE_MULTIPLIER = 0.002f;
@@ -236,6 +264,15 @@ public class CellLayout extends ViewGroup implements Dimmable {
}
x += mCellWidth + mWidthGap;
}
+
+ for (int i = 0; i < mDragRects.length; i++) {
+ int alpha = mDragRectAlphas[i];
+ if (alpha > 0) {
+ mDragRectDrawable.setAlpha(alpha);
+ mDragRectDrawable.setBounds(mDragRects[i]);
+ mDragRectDrawable.draw(canvas);
+ }
+ }
}
}
@@ -751,13 +788,23 @@ public class CellLayout extends ViewGroup implements Dimmable {
final int left = topLeft[0];
final int top = topLeft[1];
- // Now find the bottom right
- final int[] bottomRight = mTmpPoint;
- cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
- bottomRight[0] += mCellWidth;
- bottomRight[1] += mCellHeight;
- mDragRect.set(left, top, bottomRight[0], bottomRight[1]);
- invalidate();
+ final Rect dragRect = mDragRects[mDragRectCurrent];
+
+ if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) {
+ // Now find the bottom right
+ final int[] bottomRight = mTmpPoint;
+ cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
+ bottomRight[0] += mCellWidth;
+ bottomRight[1] += mCellHeight;
+
+ final int oldIndex = mDragRectCurrent;
+ mDragRectCurrent = (oldIndex + 1) % mDragRects.length;
+
+ mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]);
+
+ mDragRectAnims[oldIndex].animateOut();
+ mDragRectAnims[mDragRectCurrent].animateIn();
+ }
}
}
@@ -973,6 +1020,10 @@ public class CellLayout extends ViewGroup implements Dimmable {
if (mCrosshairsAnimator != null) {
animateCrosshairsTo(0.0f);
}
+
+ mDragRectAnims[mDragRectCurrent].animateOut();
+ mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length;
+ mDragRects[mDragRectCurrent].setEmpty();
}
/**
@@ -1015,7 +1066,6 @@ public class CellLayout extends ViewGroup implements Dimmable {
* or it may have begun on another layout.
*/
void onDragEnter(View dragView) {
- mDragRect.setEmpty();
// Fade in the drag indicators
if (mCrosshairsAnimator != null) {
animateCrosshairsTo(1.0f);
diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java
new file mode 100644
index 000000000..fb0728480
--- /dev/null
+++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 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.util.Log;
+
+/**
+ * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
+ * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
+ * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will
+ * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the
+ * interpolator in the same direction.
+ */
+public class InterruptibleInOutAnimator extends ValueAnimator {
+ private long mOriginalDuration;
+ private Object mOriginalFromValue;
+ private Object mOriginalToValue;
+
+ public InterruptibleInOutAnimator(long duration, Object fromValue, Object toValue) {
+ super(duration, fromValue, toValue);
+ mOriginalDuration = duration;
+ mOriginalFromValue = fromValue;
+ mOriginalToValue = toValue;
+ }
+
+ private void animate(Object fromValue, Object toValue) {
+ // This only makes sense when it's running in the opposite direction, or stopped.
+ setDuration(mOriginalDuration - getCurrentPlayTime());
+
+ final Object startValue = isRunning() ? getAnimatedValue() : fromValue;
+ cancel();
+ setValues(startValue, toValue);
+ start();
+ }
+
+ /**
+ * This is the equivalent of calling Animator.start(), except that it can be called when
+ * the animation is running in the opposite direction, in which case we reverse
+ * direction and animate for a correspondingly shorter duration.
+ */
+ public void animateIn() {
+ animate(mOriginalFromValue, mOriginalToValue);
+ }
+
+ /**
+ * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the
+ * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(),
+ * if the animation is currently running in the opposite direction, we reverse
+ * direction and animate for a correspondingly shorter duration.
+ */
+ public void animateOut() {
+ animate(mOriginalToValue, mOriginalFromValue);
+ }
+}