OSDN Git Service

Implementing new slider / widget interaction where frame goes around the widget
authorAdam Cohen <adamcohen@google.com>
Mon, 29 Oct 2012 01:29:17 +0000 (18:29 -0700)
committerAdam Cohen <adamcohen@google.com>
Mon, 29 Oct 2012 01:44:54 +0000 (18:44 -0700)
-> 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

policy/src/com/android/internal/policy/impl/keyguard/CheckLongPressHelper.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java

index 020fdba..4825e23 100644 (file)
@@ -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
+}
index 806c6f0..fb7beba 100644 (file)
@@ -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;
-    }
-
 }
index 20e86ad..b03e0c5 100644 (file)
@@ -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) {
index 09ce4db..539cdd1 100644 (file)
@@ -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);
 
index 3ccc7ea..a207f5d 100644 (file)
@@ -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;
index 304171c..3cd097f 100644 (file)
@@ -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