Merge "Improve interaction around showing / hiding the gear behind notifications" into nyc-dev
This commit is contained in:
@@ -517,35 +517,16 @@ public class SwipeHelper implements Gefingerpoken {
|
|||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
if (mCurrView != null) {
|
if (mCurrView == null) {
|
||||||
float maxVelocity = MAX_DISMISS_VELOCITY * mDensityScale;
|
break;
|
||||||
mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, maxVelocity);
|
}
|
||||||
float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
|
mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, getMaxVelocity());
|
||||||
float velocity = getVelocity(mVelocityTracker);
|
float velocity = getVelocity(mVelocityTracker);
|
||||||
float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
|
|
||||||
|
|
||||||
float translation = getTranslation(mCurrView);
|
if (!handleUpEvent(ev, mCurrView, velocity, getTranslation(mCurrView))) {
|
||||||
// Decide whether to dismiss the current view
|
if (isDismissGesture(ev)) {
|
||||||
boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
|
|
||||||
Math.abs(translation) > 0.4 * getSize(mCurrView);
|
|
||||||
boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
|
|
||||||
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
|
|
||||||
(velocity > 0) == (translation > 0);
|
|
||||||
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
|
|
||||||
|
|
||||||
if (mFalsingManager.isClassiferEnabled()) {
|
|
||||||
falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
|
|
||||||
} else {
|
|
||||||
falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
|
|
||||||
&& !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
|
|
||||||
&& ev.getActionMasked() == MotionEvent.ACTION_UP;
|
|
||||||
|
|
||||||
if (dismissChild) {
|
|
||||||
// flingadingy
|
// flingadingy
|
||||||
dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
|
dismissChild(mCurrView, swipedFastEnough() ? velocity : 0f);
|
||||||
} else {
|
} else {
|
||||||
// snappity
|
// snappity
|
||||||
mCallback.onDragCancelled(mCurrView);
|
mCallback.onDragCancelled(mCurrView);
|
||||||
@@ -562,6 +543,46 @@ public class SwipeHelper implements Gefingerpoken {
|
|||||||
return (int) (mFalsingThreshold * factor);
|
return (int) (mFalsingThreshold * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float getMaxVelocity() {
|
||||||
|
return MAX_DISMISS_VELOCITY * mDensityScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float getEscapeVelocity() {
|
||||||
|
return SWIPE_ESCAPE_VELOCITY * mDensityScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean swipedFarEnough() {
|
||||||
|
float translation = getTranslation(mCurrView);
|
||||||
|
return DISMISS_IF_SWIPED_FAR_ENOUGH && Math.abs(translation) > 0.4 * getSize(mCurrView);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isDismissGesture(MotionEvent ev) {
|
||||||
|
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
|
||||||
|
if (mFalsingManager.isClassiferEnabled()) {
|
||||||
|
falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
|
||||||
|
} else {
|
||||||
|
falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
|
||||||
|
}
|
||||||
|
return !falsingDetected && (swipedFastEnough() || swipedFarEnough())
|
||||||
|
&& ev.getActionMasked() == MotionEvent.ACTION_UP
|
||||||
|
&& mCallback.canChildBeDismissed(mCurrView);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean swipedFastEnough() {
|
||||||
|
float velocity = getVelocity(mVelocityTracker);
|
||||||
|
float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
|
||||||
|
float translation = getTranslation(mCurrView);
|
||||||
|
boolean ret = (Math.abs(velocity) > getEscapeVelocity()) &&
|
||||||
|
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
|
||||||
|
(velocity > 0) == (translation > 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
|
||||||
|
float translation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
View getChildAtPosition(MotionEvent ev);
|
View getChildAtPosition(MotionEvent ev);
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,18 @@ import com.android.systemui.R;
|
|||||||
|
|
||||||
public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
|
public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
|
||||||
|
|
||||||
|
private static final int GEAR_ALPHA_ANIM_DURATION = 200;
|
||||||
|
|
||||||
public interface SettingsIconRowListener {
|
public interface SettingsIconRowListener {
|
||||||
/**
|
/**
|
||||||
* Called when the gear behind a notification is touched.
|
* Called when the gear behind a notification is touched.
|
||||||
*/
|
*/
|
||||||
public void onGearTouched(ExpandableNotificationRow row, int x, int y);
|
public void onGearTouched(ExpandableNotificationRow row, int x, int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a notification is slid back over the gear.
|
||||||
|
*/
|
||||||
|
public void onSettingsIconRowReset(NotificationSettingsIconRow row);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpandableNotificationRow mParent;
|
private ExpandableNotificationRow mParent;
|
||||||
@@ -45,6 +52,8 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
private boolean mSettingsFadedIn = false;
|
private boolean mSettingsFadedIn = false;
|
||||||
private boolean mAnimating = false;
|
private boolean mAnimating = false;
|
||||||
private boolean mOnLeft = true;
|
private boolean mOnLeft = true;
|
||||||
|
private boolean mDismissing = false;
|
||||||
|
private boolean mSnapping = false;
|
||||||
private int[] mGearLocation = new int[2];
|
private int[] mGearLocation = new int[2];
|
||||||
private int[] mParentLocation = new int[2];
|
private int[] mParentLocation = new int[2];
|
||||||
|
|
||||||
@@ -78,8 +87,14 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
|
|
||||||
public void resetState() {
|
public void resetState() {
|
||||||
setGearAlpha(0f);
|
setGearAlpha(0f);
|
||||||
|
mSettingsFadedIn = false;
|
||||||
mAnimating = false;
|
mAnimating = false;
|
||||||
|
mSnapping = false;
|
||||||
|
mDismissing = false;
|
||||||
setIconLocation(true /* on left */);
|
setIconLocation(true /* on left */);
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onSettingsIconRowReset(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGearListener(SettingsIconRowListener listener) {
|
public void setGearListener(SettingsIconRowListener listener) {
|
||||||
@@ -94,19 +109,23 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
return mParent;
|
return mParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGearAlpha(float alpha) {
|
public void setGearAlpha(float alpha) {
|
||||||
if (alpha == 0) {
|
if (alpha == 0) {
|
||||||
mSettingsFadedIn = false; // Can fade in again once it's gone.
|
mSettingsFadedIn = false; // Can fade in again once it's gone.
|
||||||
setVisibility(View.INVISIBLE);
|
setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
if (alpha == 1) {
|
|
||||||
mSettingsFadedIn = true;
|
|
||||||
}
|
|
||||||
setVisibility(View.VISIBLE);
|
setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
mGearIcon.setAlpha(alpha);
|
mGearIcon.setAlpha(alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the icon is on the left side of the view or not.
|
||||||
|
*/
|
||||||
|
public boolean isIconOnLeft() {
|
||||||
|
return mOnLeft;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the horizontal space in pixels required to display the gear behind a notification.
|
* Returns the horizontal space in pixels required to display the gear behind a notification.
|
||||||
*/
|
*/
|
||||||
@@ -119,7 +138,7 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
* if entire view is visible.
|
* if entire view is visible.
|
||||||
*/
|
*/
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return mSettingsFadedIn;
|
return mGearIcon.getAlpha() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelFadeAnimator() {
|
public void cancelFadeAnimator() {
|
||||||
@@ -129,16 +148,18 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateSettingsIcons(final float transX, final float size) {
|
public void updateSettingsIcons(final float transX, final float size) {
|
||||||
if (mAnimating || (mGearIcon.getAlpha() == 0)) {
|
if (mAnimating || !mSettingsFadedIn) {
|
||||||
// Don't adjust when animating or settings aren't visible
|
// Don't adjust when animating, or if the gear hasn't been shown yet.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIconLocation(transX > 0 /* fromLeft */);
|
|
||||||
final float fadeThreshold = size * 0.3f;
|
final float fadeThreshold = size * 0.3f;
|
||||||
final float absTrans = Math.abs(transX);
|
final float absTrans = Math.abs(transX);
|
||||||
float desiredAlpha = 0;
|
float desiredAlpha = 0;
|
||||||
|
|
||||||
if (absTrans <= fadeThreshold) {
|
if (absTrans == 0) {
|
||||||
|
desiredAlpha = 0;
|
||||||
|
} else if (absTrans <= fadeThreshold) {
|
||||||
desiredAlpha = 1;
|
desiredAlpha = 1;
|
||||||
} else {
|
} else {
|
||||||
desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
|
desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
|
||||||
@@ -148,6 +169,12 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
|
|
||||||
public void fadeInSettings(final boolean fromLeft, final float transX,
|
public void fadeInSettings(final boolean fromLeft, final float transX,
|
||||||
final float notiThreshold) {
|
final float notiThreshold) {
|
||||||
|
if (mDismissing || mAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isIconLocationChange(transX)) {
|
||||||
|
setGearAlpha(0f);
|
||||||
|
}
|
||||||
setIconLocation(transX > 0 /* fromLeft */);
|
setIconLocation(transX > 0 /* fromLeft */);
|
||||||
mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
|
mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
|
||||||
mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||||
@@ -163,41 +190,54 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
mFadeAnimator.addListener(new AnimatorListenerAdapter() {
|
mFadeAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
@Override
|
|
||||||
public void onAnimationCancel(Animator animation) {
|
|
||||||
super.onAnimationCancel(animation);
|
|
||||||
mAnimating = false;
|
|
||||||
mSettingsFadedIn = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationStart(Animator animation) {
|
public void onAnimationStart(Animator animation) {
|
||||||
super.onAnimationStart(animation);
|
|
||||||
mAnimating = true;
|
mAnimating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
// TODO should animate back to 0f from current alpha
|
||||||
|
mGearIcon.setAlpha(0f);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
super.onAnimationEnd(animation);
|
|
||||||
mAnimating = false;
|
mAnimating = false;
|
||||||
mSettingsFadedIn = true;
|
mSettingsFadedIn = mGearIcon.getAlpha() == 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
|
mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
|
||||||
mFadeAnimator.setDuration(200);
|
mFadeAnimator.setDuration(GEAR_ALPHA_ANIM_DURATION);
|
||||||
mFadeAnimator.start();
|
mFadeAnimator.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIconLocation(boolean onLeft) {
|
public void setIconLocation(boolean onLeft) {
|
||||||
if (onLeft == mOnLeft) {
|
if (onLeft == mOnLeft || mSnapping) {
|
||||||
// Same side? Do nothing.
|
// Same side? Do nothing.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
|
setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
|
||||||
mOnLeft = onLeft;
|
mOnLeft = onLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIconLocationChange(float translation) {
|
||||||
|
boolean onLeft = translation > mGearIcon.getPaddingStart();
|
||||||
|
boolean onRight = translation < -mGearIcon.getPaddingStart();
|
||||||
|
if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDismissing() {
|
||||||
|
mDismissing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnapping(boolean snapping) {
|
||||||
|
mSnapping = snapping;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (v.getId() == R.id.gear_icon) {
|
if (v.getId() == R.id.gear_icon) {
|
||||||
|
|||||||
@@ -371,6 +371,11 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsIconRowReset(NotificationSettingsIconRow row) {
|
||||||
|
mSwipeHelper.setSnappedToGear(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
|
canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
|
||||||
@@ -717,11 +722,15 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
mDragAnimPendingChildren.remove(animView);
|
mDragAnimPendingChildren.remove(animView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetLeft == 0 && mCurrIconRow != null) {
|
if (mCurrIconRow != null) {
|
||||||
mCurrIconRow.resetState();
|
if (targetLeft == 0) {
|
||||||
mCurrIconRow = null;
|
mCurrIconRow.resetState();
|
||||||
if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
|
mCurrIconRow = null;
|
||||||
mGearExposedView = null;
|
if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
|
||||||
|
mGearExposedView = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mSwipeHelper.setSnappedToGear(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3379,15 +3388,11 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class NotificationSwipeHelper extends SwipeHelper {
|
private class NotificationSwipeHelper extends SwipeHelper {
|
||||||
private static final int MOVE_STATE_LEFT = -1;
|
|
||||||
private static final int MOVE_STATE_UNDEFINED = 0;
|
|
||||||
private static final int MOVE_STATE_RIGHT = 1;
|
|
||||||
|
|
||||||
private static final long GEAR_SHOW_DELAY = 60;
|
private static final long GEAR_SHOW_DELAY = 60;
|
||||||
|
|
||||||
private CheckForDrag mCheckForDrag;
|
private CheckForDrag mCheckForDrag;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
private int mMoveState = MOVE_STATE_UNDEFINED;
|
private boolean mGearSnappedTo;
|
||||||
|
private boolean mGearSnappedOnLeft;
|
||||||
|
|
||||||
public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
|
public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
|
||||||
super(swipeDirection, callback, context);
|
super(swipeDirection, callback, context);
|
||||||
@@ -3400,6 +3405,10 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
mTranslatingParentView = currView;
|
mTranslatingParentView = currView;
|
||||||
|
|
||||||
// Reset check for drag gesture
|
// Reset check for drag gesture
|
||||||
|
cancelCheckForDrag();
|
||||||
|
if (mCurrIconRow != null) {
|
||||||
|
mCurrIconRow.setSnapping(false);
|
||||||
|
}
|
||||||
mCheckForDrag = null;
|
mCheckForDrag = null;
|
||||||
mCurrIconRow = null;
|
mCurrIconRow = null;
|
||||||
|
|
||||||
@@ -3411,17 +3420,32 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
|
mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
|
||||||
mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
|
mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
|
||||||
}
|
}
|
||||||
mMoveState = MOVE_STATE_UNDEFINED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMoveUpdate(View view, float translation, float delta) {
|
public void onMoveUpdate(View view, float translation, float delta) {
|
||||||
final int newMoveState = (delta < 0) ? MOVE_STATE_RIGHT : MOVE_STATE_LEFT;
|
if (mCurrIconRow != null) {
|
||||||
if (mMoveState != MOVE_STATE_UNDEFINED && mMoveState != newMoveState) {
|
mCurrIconRow.setSnapping(false); // If we're moving, we're not snapping.
|
||||||
// Changed directions, make sure we check for drag again.
|
|
||||||
mCheckForDrag = null;
|
// If the gear is visible and the movement is towards it it's not a location change.
|
||||||
|
boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isIconOnLeft();
|
||||||
|
boolean locationChange = isTowardsGear(translation, onLeft)
|
||||||
|
? false : mCurrIconRow.isIconLocationChange(translation);
|
||||||
|
if (locationChange) {
|
||||||
|
// Don't consider it "snapped" if location has changed.
|
||||||
|
setSnappedToGear(false);
|
||||||
|
|
||||||
|
// Changed directions, make sure we check to fade in icon again.
|
||||||
|
if (!mHandler.hasCallbacks(mCheckForDrag)) {
|
||||||
|
// No check scheduled, set null to schedule a new one.
|
||||||
|
mCheckForDrag = null;
|
||||||
|
} else {
|
||||||
|
// Check scheduled, reset alpha and update location; check will fade it in
|
||||||
|
mCurrIconRow.setGearAlpha(0f);
|
||||||
|
mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mMoveState = newMoveState;
|
|
||||||
|
|
||||||
final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
|
final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
|
||||||
&& ((ExpandableNotificationRow) view).areGutsExposed();
|
&& ((ExpandableNotificationRow) view).areGutsExposed();
|
||||||
@@ -3434,35 +3458,99 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dismissChild(final View view, float velocity) {
|
public void dismissChild(final View view, float velocity) {
|
||||||
cancelCheckForDrag();
|
|
||||||
super.dismissChild(view, velocity);
|
super.dismissChild(view, velocity);
|
||||||
|
cancelCheckForDrag();
|
||||||
|
setSnappedToGear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void snapChild(final View animView, final float targetLeft, float velocity) {
|
public void snapChild(final View animView, final float targetLeft, float velocity) {
|
||||||
|
super.snapChild(animView, targetLeft, velocity);
|
||||||
|
if (targetLeft == 0) {
|
||||||
|
cancelCheckForDrag();
|
||||||
|
setSnappedToGear(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
|
||||||
|
float translation) {
|
||||||
|
if (mCurrIconRow == null) {
|
||||||
|
cancelCheckForDrag();
|
||||||
|
return false; // Let SwipeHelper handle it.
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
|
||||||
|
boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
|
||||||
|
|
||||||
|
if (mGearSnappedTo && mCurrIconRow.isVisible()) {
|
||||||
|
if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
|
||||||
|
boolean coveringGear =
|
||||||
|
Math.abs(getTranslation(animView)) <= getSpaceForGear(animView) * 0.6f;
|
||||||
|
if (gestureTowardsGear || coveringGear) {
|
||||||
|
// Gesture is towards or covering the gear
|
||||||
|
snapChild(animView, 0 /* leftTarget */, velocity);
|
||||||
|
} else if (isDismissGesture(ev)) {
|
||||||
|
// Gesture is a dismiss that's not towards the gear
|
||||||
|
dismissChild(animView, swipedFastEnough() ? velocity : 0f);
|
||||||
|
} else {
|
||||||
|
// Didn't move enough to dismiss or cover, snap to the gear
|
||||||
|
snapToGear(animView, velocity);
|
||||||
|
}
|
||||||
|
} else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
|
||||||
|
|| (gestureTowardsGear && !swipedFarEnough())) {
|
||||||
|
// The gear has been snapped to previously, however, the gear is now on the
|
||||||
|
// other side. If gesture is towards gear and not too far snap to the gear.
|
||||||
|
snapToGear(animView, velocity);
|
||||||
|
} else {
|
||||||
|
dismissOrSnapBack(animView, velocity, ev);
|
||||||
|
}
|
||||||
|
} else if ((!gestureFastEnough && swipedEnoughToShowGear(animView))
|
||||||
|
|| gestureTowardsGear) {
|
||||||
|
// Gear has not been snapped to previously and this is gear revealing gesture
|
||||||
|
snapToGear(animView, velocity);
|
||||||
|
} else {
|
||||||
|
dismissOrSnapBack(animView, velocity, ev);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dismissOrSnapBack(View animView, float velocity, MotionEvent ev) {
|
||||||
|
if (isDismissGesture(ev)) {
|
||||||
|
dismissChild(animView, swipedFastEnough() ? velocity : 0f);
|
||||||
|
} else {
|
||||||
|
snapChild(animView, 0 /* leftTarget */, velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void snapToGear(View animView, float velocity) {
|
||||||
|
final float snapBackThreshold = getSpaceForGear(animView);
|
||||||
|
final float target = mCurrIconRow.isIconOnLeft() ? snapBackThreshold
|
||||||
|
: -snapBackThreshold;
|
||||||
|
mGearExposedView = mTranslatingParentView;
|
||||||
|
if (mGearDisplayedListener != null
|
||||||
|
&& (animView instanceof ExpandableNotificationRow)) {
|
||||||
|
mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
|
||||||
|
}
|
||||||
|
if (mCurrIconRow != null) {
|
||||||
|
mCurrIconRow.setSnapping(true);
|
||||||
|
setSnappedToGear(true);
|
||||||
|
}
|
||||||
|
super.snapChild(animView, target, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean swipedEnoughToShowGear(View animView) {
|
||||||
final float snapBackThreshold = getSpaceForGear(animView);
|
final float snapBackThreshold = getSpaceForGear(animView);
|
||||||
final float translation = getTranslation(animView);
|
final float translation = getTranslation(animView);
|
||||||
final boolean fromLeft = translation > 0;
|
final boolean fromLeft = translation > 0;
|
||||||
final float absTrans = Math.abs(translation);
|
final float absTrans = Math.abs(translation);
|
||||||
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
|
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
|
||||||
|
|
||||||
boolean pastGear = (fromLeft && translation >= snapBackThreshold * 0.4f
|
// If the notification can't be dismissed then how far it can move is
|
||||||
&& translation <= notiThreshold) ||
|
// restricted -- reduce the distance it needs to move in this case.
|
||||||
(!fromLeft && absTrans >= snapBackThreshold * 0.4f
|
final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
|
||||||
&& absTrans <= notiThreshold);
|
return absTrans >= snapBackThreshold * 0.4f && absTrans <= notiThreshold;
|
||||||
|
|
||||||
if (pastGear && !isPinnedHeadsUp(animView)
|
|
||||||
&& (animView instanceof ExpandableNotificationRow)) {
|
|
||||||
// bouncity
|
|
||||||
final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
|
|
||||||
mGearExposedView = mTranslatingParentView;
|
|
||||||
if (mGearDisplayedListener != null) {
|
|
||||||
mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
|
|
||||||
}
|
|
||||||
super.snapChild(animView, target, velocity);
|
|
||||||
} else {
|
|
||||||
super.snapChild(animView, 0, velocity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -3498,6 +3586,25 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the gesture is towards the gear location or not.
|
||||||
|
*/
|
||||||
|
private boolean isTowardsGear(float velocity, boolean onLeft) {
|
||||||
|
if (mCurrIconRow == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mCurrIconRow.isVisible()
|
||||||
|
&& ((onLeft && velocity <= 0) || (!onLeft && velocity >= 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates the the gear has been snapped to.
|
||||||
|
*/
|
||||||
|
private void setSnappedToGear(boolean snapped) {
|
||||||
|
mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isIconOnLeft() : false;
|
||||||
|
mGearSnappedTo = snapped && mCurrIconRow != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the horizontal space in pixels required to display the gear behind a
|
* Returns the horizontal space in pixels required to display the gear behind a
|
||||||
* notification.
|
* notification.
|
||||||
@@ -3510,7 +3617,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkForDrag() {
|
private void checkForDrag() {
|
||||||
if (mCheckForDrag == null) {
|
if (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag)) {
|
||||||
mCheckForDrag = new CheckForDrag();
|
mCheckForDrag = new CheckForDrag();
|
||||||
mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
|
mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
|
||||||
}
|
}
|
||||||
@@ -3521,7 +3628,6 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
mCurrIconRow.cancelFadeAnimator();
|
mCurrIconRow.cancelFadeAnimator();
|
||||||
}
|
}
|
||||||
mHandler.removeCallbacks(mCheckForDrag);
|
mHandler.removeCallbacks(mCheckForDrag);
|
||||||
mCheckForDrag = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class CheckForDrag implements Runnable {
|
private final class CheckForDrag implements Runnable {
|
||||||
@@ -3531,14 +3637,13 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
final float absTransX = Math.abs(translation);
|
final float absTransX = Math.abs(translation);
|
||||||
final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
|
final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
|
||||||
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
|
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
|
||||||
if (mCurrIconRow != null && absTransX >= bounceBackToGearWidth * 0.4
|
if ((mCurrIconRow != null && (!mCurrIconRow.isVisible()
|
||||||
|
|| mCurrIconRow.isIconLocationChange(translation)))
|
||||||
|
&& absTransX >= bounceBackToGearWidth * 0.4
|
||||||
&& absTransX < notiThreshold) {
|
&& absTransX < notiThreshold) {
|
||||||
// Show icon
|
// Fade in the gear
|
||||||
mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
|
mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
|
||||||
notiThreshold);
|
notiThreshold);
|
||||||
} else {
|
|
||||||
// Allow more to be posted if this wasn't a drag.
|
|
||||||
mCheckForDrag = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3551,7 +3656,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
|||||||
|
|
||||||
final View prevGearExposedView = mGearExposedView;
|
final View prevGearExposedView = mGearExposedView;
|
||||||
mGearExposedView = null;
|
mGearExposedView = null;
|
||||||
|
mGearSnappedTo = false;
|
||||||
Animator anim = getViewTranslationAnimator(prevGearExposedView,
|
Animator anim = getViewTranslationAnimator(prevGearExposedView,
|
||||||
0 /* leftTarget */, null /* updateListener */);
|
0 /* leftTarget */, null /* updateListener */);
|
||||||
if (anim != null) {
|
if (anim != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user