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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -80,6 +90,11 @@ public class KeyguardWidgetFrame extends FrameLayout {
|
||||
mGradientPaint.setXfermode(sAddBlendMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
cancelLongPress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
// Watch for longpress events at this level to make sure
|
||||
@@ -237,12 +252,29 @@ 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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user