Handle cases for going to SHADE_LOCKED
- When the user drags down in the empty (not on a notification), we
scale up the clock in the interaction.
- If there are no notifications at all, we stay in KEYGUARD and let
the clock spring back.
- Rubberbanding is different for the case when there are no
notifications or only low-priority notifications, to indicate what
the user can expect when they lift his finger.
Bug: 16216907
Change-Id: I69d6552c96ef9e3d0d0b526bbd232d68bef47960
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 517a4e8..e9989ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
@@ -46,22 +47,23 @@
private float mInitialTouchY;
private boolean mDraggingDown;
private float mTouchSlop;
- private OnDragDownListener mOnDragDownListener;
+ private DragDownCallback mDragDownCallback;
private View mHost;
private final int[] mTemp2 = new int[2];
private boolean mDraggedFarEnough;
private ExpandableView mStartingChild;
private Interpolator mInterpolator;
+ private float mLastHeight;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
- OnDragDownListener onDragDownListener) {
+ DragDownCallback dragDownCallback) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
mInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mCallback = callback;
- mOnDragDownListener = onDragDownListener;
+ mDragDownCallback = dragDownCallback;
mHost = host;
}
@@ -86,7 +88,7 @@
captureStartingChild(mInitialTouchX, mInitialTouchY);
mInitialTouchY = y;
mInitialTouchX = x;
- mOnDragDownListener.onTouchSlopExceeded();
+ mDragDownCallback.onTouchSlopExceeded();
return true;
}
break;
@@ -104,29 +106,32 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
- final float h = y - mInitialTouchY;
+ mLastHeight = y - mInitialTouchY;
captureStartingChild(mInitialTouchX, mInitialTouchY);
if (mStartingChild != null) {
- handleExpansion(h, mStartingChild);
+ handleExpansion(mLastHeight, mStartingChild);
+ } else {
+ mDragDownCallback.setEmptyDragAmount(mLastHeight);
}
- if (h > mMinDragDistance) {
+ if (mLastHeight > mMinDragDistance) {
if (!mDraggedFarEnough) {
mDraggedFarEnough = true;
- mOnDragDownListener.onThresholdReached();
+ mDragDownCallback.onThresholdReached();
}
} else {
if (mDraggedFarEnough) {
mDraggedFarEnough = false;
- mOnDragDownListener.onDragDownReset();
+ mDragDownCallback.onDragDownReset();
}
}
return true;
case MotionEvent.ACTION_UP:
- if (mDraggedFarEnough) {
+ if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild)) {
if (mStartingChild != null) {
mCallback.setUserLockedChild(mStartingChild, false);
+ } else {
+ mDragDownCallback.setEmptyDragAmount(0f);
}
- mOnDragDownListener.onDraggedDown(mStartingChild);
mDraggingDown = false;
} else {
stopDragging();
@@ -183,12 +188,27 @@
anim.start();
}
+ private void cancelExpansion() {
+ ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0);
+ anim.setInterpolator(mInterpolator);
+ anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mDragDownCallback.setEmptyDragAmount((Float) animation.getAnimatedValue());
+ }
+ });
+ anim.start();
+ }
+
private void stopDragging() {
if (mStartingChild != null) {
cancelExpansion(mStartingChild);
+ } else {
+ cancelExpansion();
}
mDraggingDown = false;
- mOnDragDownListener.onDragDownReset();
+ mDragDownCallback.onDragDownReset();
}
private ExpandableView findView(float x, float y) {
@@ -198,10 +218,15 @@
return mCallback.getChildAtRawPosition(x, y);
}
- public interface OnDragDownListener {
- void onDraggedDown(View startingChild);
+ public interface DragDownCallback {
+
+ /**
+ * @return true if the interaction is accepted, false if it should be cancelled
+ */
+ boolean onDraggedDown(View startingChild);
void onDragDownReset();
void onThresholdReached();
void onTouchSlopExceeded();
+ void setEmptyDragAmount(float amount);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 319096d..a15d35e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -36,7 +36,6 @@
private static final float CLOCK_SCALE_FADE_END = 0.75f;
private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f;
-
private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
@@ -50,6 +49,8 @@
private int mNotificationCount;
private int mHeight;
private int mKeyguardStatusHeight;
+ private float mEmptyDragAmount;
+ private float mDensity;
/**
* The number (fractional) of notifications the "more" card counts when calculating how many
@@ -81,16 +82,18 @@
mMoreCardNotificationAmount =
(float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
res.getDimensionPixelSize(R.dimen.notification_min_height);
+ mDensity = res.getDisplayMetrics().density;
}
public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
- int notificationCount, int height, int keyguardStatusHeight) {
+ int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
mMaxKeyguardNotifications = maxKeyguardNotifications;
mMaxPanelHeight = maxPanelHeight;
mExpandedHeight = expandedHeight;
mNotificationCount = notificationCount;
mHeight = height;
mKeyguardStatusHeight = keyguardStatusHeight;
+ mEmptyDragAmount = emptyDragAmount;
}
public void run(Result result) {
@@ -116,6 +119,7 @@
float progress = distanceToScaleEnd / (startPadding - scaleEnd);
progress = Math.max(0.0f, Math.min(progress, 1.0f));
progress = mAccelerateInterpolator.getInterpolation(progress);
+ progress *= Math.pow(1 + mEmptyDragAmount / mDensity / 300, 0.3f);
return progress;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 291e692..909972a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -45,8 +45,6 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;
-import java.util.ArrayList;
-
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -112,6 +110,7 @@
private boolean mUnlockIconActive;
private int mNotificationsHeaderCollideDistance;
private int mUnlockMoveDistance;
+ private float mEmptyDragAmount;
private Interpolator mFastOutSlowInInterpolator;
private Interpolator mFastOutLinearInterpolator;
@@ -236,7 +235,8 @@
getExpandedHeight(),
mNotificationStackScroller.getNotGoneChildCount(),
getHeight(),
- mKeyguardStatusView.getHeight());
+ mKeyguardStatusView.getHeight(),
+ mEmptyDragAmount);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
startClockAnimation(mClockPositionResult.clockY);
@@ -1321,4 +1321,15 @@
public void setLaunchTransitionEndRunnable(Runnable r) {
mLaunchAnimationEndRunnable = r;
}
+
+ public void setEmptyDragAmount(float amount) {
+ float factor = 1f;
+ if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
+ factor = 0.6f;
+ } else if (!mStatusBar.hasNotifications()) {
+ factor = 0.4f;
+ }
+ mEmptyDragAmount = amount * factor;
+ positionClockAndNotifications();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a0b4b4c..2123bd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -159,7 +159,7 @@
import java.util.List;
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
- DragDownHelper.OnDragDownListener, ActivityStarter {
+ DragDownHelper.DragDownCallback, ActivityStarter {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -453,6 +453,8 @@
private Runnable mLaunchTransitionEndRunnable;
private boolean mLaunchTransitionFadingAway;
+ private boolean mHasNotifications;
+
private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
| ViewState.LOCATION_TOP_STACK_PEEKING
| ViewState.LOCATION_MAIN_AREA
@@ -1313,8 +1315,12 @@
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
- && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
- animateCollapsePanels();
+ && !mNotificationPanel.isTracking()) {
+ if (mState == StatusBarState.SHADE) {
+ animateCollapsePanels();
+ } else if (mState == StatusBarState.SHADE_LOCKED) {
+ goToKeyguard();
+ }
}
}
setAreThereNotifications();
@@ -1610,6 +1616,9 @@
findAndUpdateMediaNotifications();
updateCarrierLabelVisibility(false);
+
+ // TODO: Multiuser handling!
+ mHasNotifications = any;
}
public void findAndUpdateMediaNotifications() {
@@ -3600,8 +3609,17 @@
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@Override
- public void onDraggedDown(View startingChild) {
- goToLockedShade(startingChild);
+ public boolean onDraggedDown(View startingChild) {
+ if (mHasNotifications) {
+
+ // We have notifications, go to locked shade.
+ goToLockedShade(startingChild);
+ return true;
+ } else {
+
+ // No notifications - abort gesture.
+ return false;
+ }
}
@Override
@@ -3609,6 +3627,7 @@
mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
}
+ @Override
public void onThresholdReached() {
mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
}
@@ -3618,6 +3637,11 @@
mStackScroller.removeLongPressCallback();
}
+ @Override
+ public void setEmptyDragAmount(float amount) {
+ mNotificationPanel.setEmptyDragAmount(amount);
+ }
+
/**
* If secure with redaction: Show bouncer, go to unlocked shade.
*
@@ -3728,6 +3752,10 @@
notifyUiVisibilityChanged(mSystemUiVisibility);
}
+ public boolean hasNotifications() {
+ return mHasNotifications;
+ }
+
private final class ShadeUpdates {
private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();