diff options
| author | 2012-10-28 18:29:17 -0700 | |
|---|---|---|
| committer | 2012-10-28 18:44:54 -0700 | |
| commit | e3643138c89d49a01ba6a622ffaf71c9a95d5cdc (patch) | |
| tree | 343f6004cb14f20169b1f4644785778390394854 | |
| parent | b317db4c5c32ad419a777986bd97a659af1142d2 (diff) | |
Implementing new slider / widget interaction where frame goes around the widget
-> Frame resizes dynamically as the security slides
-> Widget shrinks immediately as the handle begins being brought up
-> Widget grows only upon security settling in the down position
-> Cleaned up a lot of state interaction between the security slider
and the widget pager / pages
-> Loosened long press slop (was using Euclidean distance by accident
instead of x crossed or y crossed logic)
Change-Id: Ic52b62e577c539327b0a65c9277300fc626cf190
6 files changed, 165 insertions, 53 deletions
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java b/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java index 020fdbabb64b..4825e23ec9c9 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java @@ -60,8 +60,10 @@ public class CheckLongPressHelper { public void onMove(MotionEvent ev) { float x = ev.getX(); float y = ev.getY(); + boolean xMoved = Math.abs(mDownX - x) > mScaledTouchSlop; + boolean yMoved = Math.abs(mDownY - y) > mScaledTouchSlop; - if (Math.sqrt(Math.pow(mDownX - x, 2) + Math.pow(mDownY - y, 2)) > mScaledTouchSlop) { + if (xMoved || yMoved) { cancelLongPress(); } } @@ -77,4 +79,4 @@ public class CheckLongPressHelper { public boolean hasPerformedLongPress() { return mHasPerformedLongPress; } -}
\ No newline at end of file +} diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java index 806c6f096fee..fb7bebaa5b85 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java @@ -22,7 +22,6 @@ import android.view.View; public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChallengeScrolledListener { private KeyguardWidgetPager mPagedView; - private int mCurrentPageIndex; private ChallengeLayout mChallengeLayout; private Runnable mHideHintsRunnable; private KeyguardSecurityView mKeyguardSecurityContainer; @@ -31,6 +30,12 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle private static final int SCREEN_ON_RING_HINT_DELAY = 300; Handler mMainQueue = new Handler(Looper.myLooper()); + int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE; + + // Paged view state + private int mPageListeningToSlider = -1; + private int mCurrentPage = -1; + int mChallengeTop = 0; public KeyguardViewStateManager() { @@ -66,28 +71,39 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle } public void onPageSwitch(View newPage, int newPageIndex) { - // Reset the previous page size and ensure the current page is sized appropriately - if (mPagedView != null) { - KeyguardWidgetFrame oldPage = mPagedView.getWidgetPageAt(mCurrentPageIndex); - // Reset the old widget page to full size - if (oldPage != null) { - oldPage.resetSize(); + // Reset the previous page size and ensure the current page is sized appropriately. + // We only modify the page state if it is not currently under control by the slider. + // This prevents conflicts. + if (mPagedView != null && mChallengeLayout != null) { + KeyguardWidgetFrame prevPage = mPagedView.getWidgetPageAt(mCurrentPage); + if (prevPage != null && mCurrentPage != mPageListeningToSlider) { + prevPage.resetSize(); } KeyguardWidgetFrame newCurPage = mPagedView.getWidgetPageAt(newPageIndex); - if (mChallengeLayout.isChallengeOverlapping()) { - sizeWidgetFrameToChallengeTop(newCurPage); + boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); + if (challengeOverlapping && !newCurPage.isSmall() + && mPageListeningToSlider != newPageIndex) { + shrinkWidget(newCurPage); } } - mCurrentPageIndex = newPageIndex; + mCurrentPage = newPageIndex; } - private void sizeWidgetFrameToChallengeTop(KeyguardWidgetFrame frame) { - if (frame == null) return; + private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) { mTmpPoint[0] = 0; - mTmpPoint[1] = mChallengeTop; + mTmpPoint[1] = top; mapPoint((View) mChallengeLayout, frame, mTmpPoint); - frame.setChallengeTop(mTmpPoint[1]); + return mTmpPoint[1]; + } + + private void shrinkWidget(KeyguardWidgetFrame frame) { + if (frame != null && mChallengeLayout != null && + mChallengeLayout instanceof SlidingChallengeLayout) { + SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout; + int top = scl.getMaxChallengeTop(); + frame.shrinkWidget(getChallengeTopRelativeToFrame(frame, top)); + } } /** @@ -114,20 +130,17 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle @Override public void onScrollStateChanged(int scrollState) { + if (mPagedView == null || mChallengeLayout == null) return; + boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); + if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) { - if (mPagedView == null) return; + KeyguardWidgetFrame frame = mPagedView.getWidgetPageAt(mPageListeningToSlider); + if (frame == null) return; - boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping(); - int curPage = mPagedView.getCurrentPage(); - KeyguardWidgetFrame frame = mPagedView.getWidgetPageAt(curPage); - - if (frame != null) { - if (!challengeOverlapping) { - frame.resetSize(); - } else { - sizeWidgetFrameToChallengeTop(frame); - } + if (!challengeOverlapping) { + frame.resetSize(); } + frame.hideFrame(this); if (challengeOverlapping) { mPagedView.setOnlyAllowEdgeSwipes(true); @@ -140,10 +153,38 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle } else { mKeyguardSecurityContainer.onPause(); } - } else { + mPageListeningToSlider = -1; + } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) { + // Whether dragging or settling, if the last state was idle, we use this signal + // to update the current page who will receive events from the sliding challenge. + // We resize the frame as appropriate. + mPageListeningToSlider = mPagedView.getNextPage(); + KeyguardWidgetFrame frame = mPagedView.getWidgetPageAt(mPageListeningToSlider); + if (frame == null) return; + + frame.showFrame(this); + + // As soon as the security begins sliding, the widget becomes small (if it wasn't + // small to begin with). + if (!frame.isSmall()) { + // We need to fetch the final page, in case the pages are in motion. + mPageListeningToSlider = mPagedView.getNextPage(); + System.out.println("Shrink widget from scroll state changed!"); + shrinkWidget(frame); + } // View is on the move. Pause the security view until it completes. mKeyguardSecurityContainer.onPause(); } + mLastScrollState = scrollState; + } + + @Override + public void onScrollPositionChanged(float scrollPosition, int challengeTop) { + mChallengeTop = challengeTop; + KeyguardWidgetFrame frame = mPagedView.getWidgetPageAt(mPageListeningToSlider); + if (frame != null) { + frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop)); + } } public void showUsabilityHints() { @@ -164,10 +205,4 @@ public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChalle mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION); } - - @Override - public void onScrollPositionChanged(float scrollPosition, int challengeTop) { - mChallengeTop = challengeTop; - } - } 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 20e86ad5475d..b03e0c5afeea 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java @@ -16,6 +16,9 @@ package com.android.internal.policy.impl.keyguard; +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.appwidget.AppWidgetHostView; import android.content.Context; import android.content.res.Resources; @@ -49,6 +52,8 @@ public class KeyguardWidgetFrame extends FrameLayout { private final Rect mForegroundRect = new Rect(); private int mForegroundAlpha = 0; private CheckLongPressHelper mLongPressHelper; + private Animator mFrameFade; + private boolean mIsSmall = false; private float mBackgroundAlpha; private float mContentAlpha; @@ -56,6 +61,11 @@ public class KeyguardWidgetFrame extends FrameLayout { private Drawable mBackgroundDrawable; private Rect mBackgroundRect = new Rect(); + // 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. + private Object mBgAlphaController; + public KeyguardWidgetFrame(Context context) { this(context, null, 0); } @@ -81,6 +91,11 @@ public class KeyguardWidgetFrame extends FrameLayout { } @Override + protected void onDetachedFromWindow() { + cancelLongPress(); + } + + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // Watch for longpress events at this level to make sure // users can always pick up this widget @@ -238,11 +253,28 @@ public class KeyguardWidgetFrame extends FrameLayout { } /** + * Set the top location of the challenge. + * + * @param top The top of the challenge, in _local_ coordinates, or -1 to indicate the challenge + * is down. + */ + private void setChallengeTop(int top, boolean updateWidgetSize) { + // The widget starts below the padding, and extends to the top of the challengs. + int widgetHeight = top - getPaddingTop(); + int frameHeight = top + getPaddingBottom(); + setFrameHeight(frameHeight); + if (updateWidgetSize) { + setWidgetHeight(widgetHeight); + } + } + + /** * Depending on whether the security is up, the widget size needs to change * * @param height The height of the widget, -1 for full height */ - public void setWidgetHeight(int height) { + private void setWidgetHeight(int height) { + System.out.println("Set widget height: " + this + " : " + height); boolean needLayout = false; View widget = getContent(); if (widget != null) { @@ -257,22 +289,56 @@ public class KeyguardWidgetFrame extends FrameLayout { } } - /** - * Set the top location of the challenge. - * - * @param top The top of the challenge, in _local_ coordinates, or -1 to indicate the challenge - * is down. - */ - public void setChallengeTop(int top) { - // The widget starts below the padding, and extends to the top of the challengs. - int widgetHeight = top - getPaddingTop(); - setWidgetHeight(widgetHeight); + public boolean isSmall() { + return mIsSmall; + } + + public void adjustFrame(int challengeTop) { + setChallengeTop(challengeTop, false); + } + + public void shrinkWidget(int challengeTop) { + mIsSmall = true; + setChallengeTop(challengeTop, true); } public void resetSize() { + mIsSmall = false; + setFrameHeight(getMeasuredHeight()); setWidgetHeight(LayoutParams.MATCH_PARENT); } + public void setFrameHeight(int height) { + height = Math.min(height, getMeasuredHeight()); + mBackgroundRect.set(0, 0, getMeasuredWidth(), height); + invalidate(); + } + + public void hideFrame(Object caller) { + fadeFrame(caller, false, 0f, 150); + } + + public void showFrame(Object caller) { + fadeFrame(caller, true, 1f, 150); + } + + public void fadeFrame(Object caller, boolean takeControl, float alpha, int duration) { + if (takeControl) { + mBgAlphaController = caller; + } + + if (mBgAlphaController != caller) return; + + if (mFrameFade != null) { + mFrameFade.cancel(); + mFrameFade = null; + } + PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", alpha); + mFrameFade = ObjectAnimator.ofPropertyValuesHolder(this, bgAlpha); + mFrameFade.setDuration(duration); + mFrameFade.start(); + } + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); @@ -285,6 +351,7 @@ public class KeyguardWidgetFrame extends FrameLayout { mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f, mGradientColor, 0, Shader.TileMode.CLAMP); mBackgroundRect.set(0, 0, w, h); + invalidate(); } void setOverScrollAmount(float r, boolean left) { 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 09ce4db4e10b..539cdd1fcaad 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java @@ -433,9 +433,11 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit int count = getChildCount(); PropertyValuesHolder alpha; - PropertyValuesHolder outlineAlpha; ArrayList<Animator> anims = new ArrayList<Animator>(); + int duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION : + CHILDREN_OUTLINE_FADE_OUT_DURATION; + int curPage = getNextPage(); for (int i = 0; i < count; i++) { float finalContentAlpha; @@ -446,16 +448,15 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit } else { finalContentAlpha = 0f; } - float finalOutlineAlpha = show ? getAlphaForPage(mScreenCenter, i) : 0f; KeyguardWidgetFrame child = getWidgetPageAt(i); alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha); - outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",finalOutlineAlpha); - ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha); + ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha); anims.add(a); + + float finalOutlineAlpha = show ? getAlphaForPage(mScreenCenter, i) : 0f; + child.fadeFrame(this, show, finalOutlineAlpha, duration); } - int duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION : - CHILDREN_OUTLINE_FADE_OUT_DURATION; mChildrenOutlineFadeAnimation = new AnimatorSet(); mChildrenOutlineFadeAnimation.playTogether(anims); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java index 3ccc7ea55ef8..a207f5d1048d 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java index 304171c28dab..3cd097fbbee6 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java @@ -374,7 +374,7 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout mScrollState = state; animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); - animateFrame(state != SCROLL_STATE_IDLE, false); + animateFrame(false , false); if (mScrollListener != null) { mScrollListener.onScrollStateChanged(state); } @@ -845,6 +845,14 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout } } + public int getMaxChallengeTop() { + if (mChallengeView == null) return 0; + + final int layoutBottom = getLayoutBottom(); + final int challengeHeight = mChallengeView.getHeight(); + return layoutBottom - challengeHeight; + } + /** * Move the bottom edge of mChallengeView to a new position and notify the listener * if it represents a change in position. Changes made through this method will |