diff options
author | Winson Chung <winsonc@google.com> | 2012-11-01 14:48:51 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2012-11-02 10:41:41 -0700 |
commit | f3b9ec8230298e8f707c2fc44a74fb9346ec3d12 (patch) | |
tree | ad686ed338db14c39bbd88d12e6e625bf7cc62bf | |
parent | febea58c9215c38fde2c89732b88c832ab69c143 (diff) | |
download | frameworks_base-f3b9ec8230298e8f707c2fc44a74fb9346ec3d12.tar.gz frameworks_base-f3b9ec8230298e8f707c2fc44a74fb9346ec3d12.tar.bz2 frameworks_base-f3b9ec8230298e8f707c2fc44a74fb9346ec3d12.zip |
Initial changes to allow dropping on delete target to remove widget.
- Fixing deletion animation
Change-Id: Ie93991c0e9af0c6b64c6b3808e38f349f6845965
14 files changed, 337 insertions, 80 deletions
diff --git a/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png Binary files differnew file mode 100644 index 00000000000..84549ff946a --- /dev/null +++ b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png diff --git a/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png Binary files differnew file mode 100644 index 00000000000..219f3e5cfd6 --- /dev/null +++ b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png diff --git a/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png Binary files differnew file mode 100644 index 00000000000..d4965d9f804 --- /dev/null +++ b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml index 67ac1d5298c..be1d5b6c5ce 100644 --- a/core/res/res/layout-land/keyguard_host_view.xml +++ b/core/res/res/layout-land/keyguard_host_view.xml @@ -33,6 +33,12 @@ android:layout_height="match_parent" android:clipChildren="false"> + <include layout="@layout/keyguard_widget_remove_drop_target" + android:id="@+id/keyguard_widget_pager_delete_target" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|center_horizontal" /> + <include layout="@layout/keyguard_widget_pager" android:id="@+id/app_widget_container" android:layout_width="match_parent" diff --git a/core/res/res/layout-land/keyguard_widget_pager.xml b/core/res/res/layout-land/keyguard_widget_pager.xml index 975288fa4cc..02c6d0e8d27 100644 --- a/core/res/res/layout-land/keyguard_widget_pager.xml +++ b/core/res/res/layout-land/keyguard_widget_pager.xml @@ -25,7 +25,6 @@ android:paddingRight="25dp" android:paddingTop="25dp" android:paddingBottom="25dp" - android:clipChildren="false" android:clipToPadding="false" androidprv:pageSpacing="10dp"> </com.android.internal.policy.impl.keyguard.KeyguardWidgetCarousel>
\ No newline at end of file diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml index b3270e0d9d3..9921313bb72 100644 --- a/core/res/res/layout-port/keyguard_host_view.xml +++ b/core/res/res/layout-port/keyguard_host_view.xml @@ -35,6 +35,16 @@ <FrameLayout android:layout_width="match_parent" + android:layout_height="wrap_content"> + <include layout="@layout/keyguard_widget_remove_drop_target" + android:id="@+id/keyguard_widget_pager_delete_target" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|center_horizontal" /> + </FrameLayout> + + <FrameLayout + android:layout_width="match_parent" android:layout_height="match_parent" androidprv:layout_childType="widgets"> <include layout="@layout/keyguard_widget_pager" diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml index 7fd370b6bdb..7f22709a0d7 100644 --- a/core/res/res/layout-port/keyguard_widget_pager.xml +++ b/core/res/res/layout-port/keyguard_widget_pager.xml @@ -26,7 +26,6 @@ android:paddingRight="25dp" android:paddingTop="25dp" android:paddingBottom="@dimen/kg_widget_pager_bottom_padding" - android:clipChildren="false" android:clipToPadding="false" androidprv:pageSpacing="10dp"> </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager> diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml index 5d858ae2ef1..809104d6e0f 100644 --- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml +++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml @@ -34,6 +34,12 @@ android:clipChildren="false" android:orientation="vertical"> + <include layout="@layout/keyguard_widget_remove_drop_target" + android:id="@+id/keyguard_widget_pager_delete_target" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|center_horizontal" /> + <include layout="@layout/keyguard_widget_pager" android:id="@+id/app_widget_container" android:layout_width="match_parent" diff --git a/core/res/res/layout/keyguard_widget_remove_drop_target.xml b/core/res/res/layout/keyguard_widget_remove_drop_target.xml new file mode 100644 index 00000000000..c4fe9e0fe50 --- /dev/null +++ b/core/res/res/layout/keyguard_widget_remove_drop_target.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2012, 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. +*/ +--> +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center" + android:padding="20dp" + android:paddingLeft="40dp" + android:paddingRight="40dp" + android:drawableLeft="@drawable/kg_widget_delete_drop_target" + android:drawablePadding="4dp" + android:textColor="#FFF" + android:textSize="13sp" + android:shadowColor="#000" + android:shadowDy="1.0" + android:shadowRadius="1.0" + android:visibility="gone" />
\ No newline at end of file diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index adf53a94b86..a12c14cf6fc 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1319,6 +1319,7 @@ <java-symbol type="id" name="keyguard_sim_puk_view" /> <java-symbol type="id" name="keyguard_account_view" /> <java-symbol type="id" name="keyguard_selector_fade_container" /> + <java-symbol type="id" name="keyguard_widget_pager_delete_target" /> <java-symbol type="id" name="app_widget_container" /> <java-symbol type="id" name="view_flipper" /> <java-symbol type="id" name="emergency_call_button" /> diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index 08d388b8363..d28656410d9 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -150,9 +150,11 @@ public class KeyguardHostView extends KeyguardViewBase { protected void onFinishInflate() { // Grab instances of and make any necessary changes to the main layouts. Create // view state manager and wire up necessary listeners / callbacks. + View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target); mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container); mAppWidgetContainer.setVisibility(VISIBLE); mAppWidgetContainer.setCallbacks(mWidgetCallbacks); + mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget); mAppWidgetContainer.setMinScale(0.5f); SlidingChallengeLayout slider = diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java index b6ea9baa409..9ffabf8f58c 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java @@ -43,6 +43,10 @@ public class KeyguardWidgetFrame extends FrameLayout { new PorterDuffXfermode(PorterDuff.Mode.ADD); static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f; + static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000; + + // Temporarily disable this for the time being until we know why the gfx is messing up + static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true; private int mGradientColor; private LinearGradient mForegroundGradient; @@ -76,6 +80,8 @@ public class KeyguardWidgetFrame extends FrameLayout { // This will hold the width value before we've actually been measured private int mFrameHeight; + private boolean mIsHoveringOverDeleteDropTarget; + // Multiple callers may try and adjust the alpha of the frame. When a caller shows // the outlines, we give that caller control, and nobody else can fade them out. // This prevents animation conflicts. @@ -110,6 +116,15 @@ public class KeyguardWidgetFrame extends FrameLayout { cancelLongPress(); } + void setIsHoveringOverDeleteDropTarget(boolean isHovering) { + if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { + if (mIsHoveringOverDeleteDropTarget != isHovering) { + mIsHoveringOverDeleteDropTarget = isHovering; + invalidate(); + } + } + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Watch for longpress events at this level to make sure @@ -171,6 +186,12 @@ public class KeyguardWidgetFrame extends FrameLayout { c.drawRect(mForegroundRect, mGradientPaint); } + private void drawHoveringOverDeleteOverlay(Canvas c) { + if (mIsHoveringOverDeleteDropTarget) { + c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR); + } + } + protected void drawBg(Canvas canvas) { if (mBackgroundAlpha > 0.0f) { Drawable bg = mBackgroundDrawable; @@ -183,9 +204,16 @@ public class KeyguardWidgetFrame extends FrameLayout { @Override protected void dispatchDraw(Canvas canvas) { + if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { + canvas.save(); + } drawBg(canvas); super.dispatchDraw(canvas); drawGradientOverlay(canvas); + if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) { + drawHoveringOverDeleteOverlay(canvas); + canvas.restore(); + } } /** diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java index a6d1a029cc0..acb2913a678 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java @@ -717,4 +717,10 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit return indexOfChild((KeyguardWidgetFrame)view.getParent()); } } + + @Override + protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) { + KeyguardWidgetFrame child = getWidgetPageAt(viewIndex); + child.setIsHoveringOverDeleteDropTarget(isHovering); + } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java index bad50e8616f..00a0aede580 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java @@ -48,6 +48,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import android.widget.Scroller; import com.android.internal.R; @@ -205,6 +206,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected int REORDERING_ZOOM_IN_OUT_DURATION = 250; private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300; private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f; + private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150; private float mMinScale = 1f; protected View mDragView; private AnimatorSet mZoomInOutAnim; @@ -228,15 +230,21 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Convenience/caching private Matrix mTmpInvMatrix = new Matrix(); private float[] mTmpPoint = new float[2]; + private Rect mTmpRect = new Rect(); // Fling to delete private int FLING_TO_DELETE_FADE_OUT_DURATION = 350; private float FLING_TO_DELETE_FRICTION = 0.035f; // The degrees specifies how much deviation from the up vector to still consider a fling "up" - private float FLING_TO_DELETE_MAX_FLING_DEGREES = 35f; - private int FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250; + private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f; protected int mFlingToDeleteThresholdVelocity = -1400; - private boolean mIsFlingingToDelete = false; + // Drag to delete + private boolean mDeferringForDelete = false; + private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250; + private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350; + + // Drop to delete + private View mDeleteDropTarget; public interface PageSwitchListener { void onPageSwitching(View newPage, int newPageIndex); @@ -294,19 +302,23 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc setOnHierarchyChangeListener(this); } + void setDeleteDropTarget(View v) { + mDeleteDropTarget = v; + } + // Convenience methods to map points from self to parent and vice versa - float[] mapPointFromSelfToParent(float x, float y) { + float[] mapPointFromViewToParent(View v, float x, float y) { mTmpPoint[0] = x; mTmpPoint[1] = y; - getMatrix().mapPoints(mTmpPoint); - mTmpPoint[0] += getLeft(); - mTmpPoint[1] += getTop(); + v.getMatrix().mapPoints(mTmpPoint); + mTmpPoint[0] += v.getLeft(); + mTmpPoint[1] += v.getTop(); return mTmpPoint; } - float[] mapPointFromParentToSelf(float x, float y) { - mTmpPoint[0] = x - getLeft(); - mTmpPoint[1] = y - getTop(); - getMatrix().invert(mTmpInvMatrix); + float[] mapPointFromParentToView(View v, float x, float y) { + mTmpPoint[0] = x - v.getLeft(); + mTmpPoint[1] = y - v.getTop(); + v.getMatrix().invert(mTmpInvMatrix); mTmpInvMatrix.mapPoints(mTmpPoint); return mTmpPoint; } @@ -329,7 +341,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc public void setScaleX(float scaleX) { super.setScaleX(scaleX); if (isReordering(true)) { - float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY); + float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); mLastMotionX = p[0]; mLastMotionY = p[1]; updateDragViewTranslationDuringDrag(); @@ -519,7 +531,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Update the last motion events when scrolling if (isReordering(true)) { - float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY); + float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); mLastMotionX = p[0]; mLastMotionY = p[1]; updateDragViewTranslationDuringDrag(); @@ -547,6 +559,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mTouchState == TOUCH_STATE_REST) { pageEndMoving(); } + onPostReorderingAnimationCompleted(); return true; } @@ -640,7 +653,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // ensure that the cache is filled with good values. invalidateCachedOffsets(); - if (mChildCountOnLastMeasure != getChildCount() && !mIsFlingingToDelete) { + if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) { setCurrentPage(mCurrentPage); } mChildCountOnLastMeasure = getChildCount(); @@ -864,7 +877,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final int pageCount = getChildCount(); if (pageCount > 0) { getVisiblePages(mTempVisiblePagesRange); - boundByReorderablePages(isReordering(false), mTempVisiblePagesRange); final int leftScreen = mTempVisiblePagesRange[0]; final int rightScreen = mTempVisiblePagesRange[1]; if (leftScreen != -1 && rightScreen != -1) { @@ -1046,7 +1058,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mDownScrollX = getScrollX(); mLastMotionX = x; mLastMotionY = y; - float[] p = mapPointFromSelfToParent(x, y); + float[] p = mapPointFromViewToParent(this, x, y); mParentDownMotionX = p[0]; mParentDownMotionY = p[1]; mLastMotionXRemainder = 0; @@ -1278,7 +1290,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mDownMotionX = mLastMotionX = ev.getX(); mDownMotionY = mLastMotionY = ev.getY(); mDownScrollX = getScrollX(); - float[] p = mapPointFromSelfToParent(mLastMotionX, mLastMotionY); + float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); mParentDownMotionX = p[0]; mParentDownMotionY = p[1]; mLastMotionXRemainder = 0; @@ -1330,7 +1342,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Update the parent down so that our zoom animations take this new movement into // account - float[] pt = mapPointFromSelfToParent(mLastMotionX, mLastMotionY); + float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); mParentDownMotionX = pt[0]; mParentDownMotionY = pt[1]; updateDragViewTranslationDuringDrag(); @@ -1339,11 +1351,16 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final int dragViewIndex = indexOfChild(mDragView); int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE * getViewportWidth()); - int leftBufferEdge = (int) (mapPointFromSelfToParent(mViewport.left, 0)[0] + int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0] + bufferSize); - int rightBufferEdge = (int) (mapPointFromSelfToParent(mViewport.right, 0)[0] + int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0] - bufferSize); + // Change the drag view if we are hovering over the drop target + boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget( + (int) mParentDownMotionX, (int) mParentDownMotionY); + setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete); + if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge); if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge); if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX); @@ -1360,7 +1377,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } final int pageUnderPointIndex = pageIndexToSnapTo; - if (pageUnderPointIndex > -1) { + if (pageUnderPointIndex > -1 && !isHoveringOverDelete) { mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; boundByReorderablePages(true, mTempVisiblePagesRange); @@ -1493,13 +1510,29 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc snapToDestination(); } } else if (mTouchState == TOUCH_STATE_REORDERING) { + // Update the last motion position + mLastMotionX = ev.getX(); + mLastMotionY = ev.getY(); + + // Update the parent down so that our zoom animations take this new movement into + // account + float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); + mParentDownMotionX = pt[0]; + mParentDownMotionY = pt[1]; + updateDragViewTranslationDuringDrag(); + boolean handledFling = false; if (!DISABLE_FLING_TO_DELETE) { // Check the velocity and see if we are flinging-to-delete PointF flingToDeleteVector = isFlingingToDelete(); if (flingToDeleteVector != null) { onFlingToDelete(flingToDeleteVector); + handledFling = true; } } + if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, + (int) mParentDownMotionY)) { + onDropToDelete(); + } } else { onUnhandledTap(ev); } @@ -1776,6 +1809,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc computeScroll(); } + mForceScreenScrolled = true; invalidate(); } @@ -1999,6 +2033,23 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mZoomInOutAnim.playTogether( ObjectAnimator.ofFloat(this, "scaleX", mMinScale), ObjectAnimator.ofFloat(this, "scaleY", mMinScale)); + mZoomInOutAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Show the delete drop target + if (mDeleteDropTarget != null) { + mDeleteDropTarget.setVisibility(View.VISIBLE); + mDeleteDropTarget.animate().alpha(1f) + .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mDeleteDropTarget.setAlpha(0f); + } + }); + } + } + }); mZoomInOutAnim.start(); return true; } @@ -2015,6 +2066,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mTouchState = TOUCH_STATE_REORDERING; mIsReordering = true; + // Mark all the non-widget pages as invisible + getVisiblePages(mTempVisiblePagesRange); + boundByReorderablePages(true, mTempVisiblePagesRange); + for (int i = 0; i < getPageCount(); ++i) { + if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { + getPageAt(i).setAlpha(0f); + } + } + // We must invalidate to trigger a redraw to update the layers such that the drag view // is always drawn on top invalidate(); @@ -2036,6 +2096,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc R.string.keyguard_accessibility_widget_reorder_end)); } mIsReordering = false; + + // Mark all the non-widget pages as visible again + getVisiblePages(mTempVisiblePagesRange); + boundByReorderablePages(true, mTempVisiblePagesRange); + for (int i = 0; i < getPageCount(); ++i) { + if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { + getPageAt(i).setAlpha(1f); + } + } } public boolean startReordering() { @@ -2080,7 +2149,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc onEndReordering(); } }; - if (!mIsFlingingToDelete) { + if (!mDeferringForDelete) { mPostReorderingPreZoomInRunnable = new Runnable() { public void run() { zoomIn(onCompleteRunnable); @@ -2094,7 +2163,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Animate the drag view back to the front position animateDragViewToOriginalPosition(); } else { - zoomIn(onCompleteRunnable); + // Handled in post-delete-animation-callbacks } } @@ -2111,6 +2180,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc ObjectAnimator.ofFloat(this, "scaleY", 1f)); mZoomInOutAnim.addListener(new AnimatorListenerAdapter() { @Override + public void onAnimationStart(Animator animation) { + // Hide the delete drop target + if (mDeleteDropTarget != null) { + mDeleteDropTarget.animate().alpha(0f) + .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mDeleteDropTarget.setVisibility(View.GONE); + } + }); + } + } + @Override public void onAnimationCancel(Animator animation) { mDragView = null; } @@ -2194,6 +2277,97 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } }; + private Runnable createPostDeleteAnimationRunnable(final View dragView) { + return new Runnable() { + @Override + public void run() { + int dragViewIndex = indexOfChild(dragView); + + // For each of the pages around the drag view, animate them from the previous + // position to the new position in the layout (as a result of the drag view moving + // in the layout) + // NOTE: We can make an assumption here because we have side-bound pages that we + // will always have pages to animate in from the left + getVisiblePages(mTempVisiblePagesRange); + boundByReorderablePages(true, mTempVisiblePagesRange); + boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]); + boolean slideFromLeft = (isLastWidgetPage || + dragViewIndex > mTempVisiblePagesRange[0]); + + // Setup the scroll to the correct page before we swap the views + if (slideFromLeft) { + snapToPageImmediately(dragViewIndex - 1); + } + + int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]); + int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1); + int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 ); + int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex); + ArrayList<Animator> animations = new ArrayList<Animator>(); + for (int i = lowerIndex; i <= upperIndex; ++i) { + View v = getChildAt(i); + // dragViewIndex < pageUnderPointIndex, so after we remove the + // drag view all subsequent views to pageUnderPointIndex will + // shift down. + int oldX = 0; + int newX = 0; + if (slideFromLeft) { + if (i == 0) { + // Simulate the page being offscreen with the page spacing + oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i) + - mPageSpacing; + } else { + oldX = getViewportOffsetX() + getChildOffset(i - 1); + } + newX = getViewportOffsetX() + getChildOffset(i); + } else { + oldX = getChildOffset(i) - getChildOffset(i - 1); + newX = 0; + } + + // Animate the view translation from its old position to its new + // position + AnimatorSet anim = (AnimatorSet) v.getTag(); + if (anim != null) { + anim.cancel(); + } + + // Note: Hacky, but we want to skip any optimizations to not draw completely + // hidden views + v.setAlpha(Math.max(v.getAlpha(), 0.01f)); + v.setTranslationX(oldX - newX); + anim = new AnimatorSet(); + anim.playTogether( + ObjectAnimator.ofFloat(v, "translationX", 0f), + ObjectAnimator.ofFloat(v, "alpha", 1f)); + animations.add(anim); + v.setTag(anim); + } + + AnimatorSet slideAnimations = new AnimatorSet(); + slideAnimations.playTogether(animations); + slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION); + slideAnimations.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + final Runnable onCompleteRunnable = new Runnable() { + @Override + public void run() { + mDeferringForDelete = false; + onEndReordering(); + } + }; + zoomIn(onCompleteRunnable); + } + }); + slideAnimations.start(); + + removeView(dragView); + onRemoveView(dragView); + } + }; + } + public void onFlingToDelete(PointF vel) { final long startTime = AnimationUtils.currentAnimationTimeMillis(); @@ -2230,59 +2404,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel, from, startTime, FLING_TO_DELETE_FRICTION); - final Runnable onAnimationEndRunnable = new Runnable() { - @Override - public void run() { - int dragViewIndex = indexOfChild(dragView); - // Setup the scroll to the correct page before we swap the views - snapToPageImmediately(dragViewIndex - 1); - - // For each of the pages around the drag view, animate them from the previous - // position to the new position in the layout (as a result of the drag view moving - // in the layout) - // NOTE: We can make an assumption here because we have side-bound pages that we - // will always have pages to animate in from the left - int lowerIndex = 0; - int upperIndex = dragViewIndex - 1; - for (int i = lowerIndex; i <= upperIndex; ++i) { - View v = getChildAt(i); - // dragViewIndex < pageUnderPointIndex, so after we remove the - // drag view all subsequent views to pageUnderPointIndex will - // shift down. - int oldX = 0; - if (i == 0) { - oldX = -(getViewportOffsetX() + getChildOffset(i)); - } else { - oldX = getViewportOffsetX() + getChildOffset(i - 1); - } - int newX = getViewportOffsetX() + getChildOffset(i); - - // Animate the view translation from its old position to its new - // position - AnimatorSet anim = (AnimatorSet) v.getTag(); - if (anim != null) { - anim.cancel(); - } - - v.setTranslationX(oldX - newX); - anim = new AnimatorSet(); - anim.setDuration(FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION); - anim.playTogether( - ObjectAnimator.ofFloat(v, "translationX", 0f)); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mIsFlingingToDelete = false; - } - }); - anim.start(); - v.setTag(anim); - } - - removeView(dragView); - onRemoveView(dragView); - } - }; + final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView); // Create and start the animation ValueAnimator mDropAnim = new ValueAnimator(); @@ -2296,11 +2418,57 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } }); mDropAnim.start(); - mIsFlingingToDelete = true; + mDeferringForDelete = true; } - /* Accessibility */ + /* Drag to delete */ + private boolean isHoveringOverDeleteDropTarget(int x, int y) { + if (mDeleteDropTarget != null) { + mDeleteDropTarget.getGlobalVisibleRect(mTmpRect); + return mTmpRect.contains(x, y); + } + return false; + } + + protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {} + + private void onDropToDelete() { + final View dragView = mDragView; + final float toScale = 0f; + final float toAlpha = 0f; + + // Create and start the complex animation + ArrayList<Animator> animations = new ArrayList<Animator>(); + AnimatorSet motionAnim = new AnimatorSet(); + motionAnim.setInterpolator(new DecelerateInterpolator(2)); + motionAnim.playTogether( + ObjectAnimator.ofFloat(dragView, "scaleX", toScale), + ObjectAnimator.ofFloat(dragView, "scaleY", toScale)); + animations.add(motionAnim); + + AnimatorSet alphaAnim = new AnimatorSet(); + alphaAnim.setInterpolator(new LinearInterpolator()); + alphaAnim.playTogether( + ObjectAnimator.ofFloat(dragView, "alpha", toAlpha)); + animations.add(alphaAnim); + + final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView); + + AnimatorSet anim = new AnimatorSet(); + anim.playTogether(animations); + anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION); + anim.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + onAnimationEndRunnable.run(); + } + }); + anim.start(); + + mDeferringForDelete = true; + } + + /* Accessibility */ @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); |