Introducing new PulseExpansionHandler for dragging down while pulsing
This also uses the same wake-up animation now when we're pulsing.
Test: atest SystemUITests
Bug: 125942236
Change-Id: I34a0eff6ecc2280aa983740e4273b344d073ca6e
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
index 46e004c..0db5bef 100644
--- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java
@@ -380,6 +380,20 @@
addEvent(PhoneEvent.ON_NOTIFICATION_START_DRAGGING_DOWN);
}
+ public void onStartExpandingFromPulse() {
+ if (DEBUG) {
+ Log.d(TAG, "onStartExpandingFromPulse");
+ }
+ // TODO: maybe add event
+ }
+
+ public void onExpansionFromPulseStopped() {
+ if (DEBUG) {
+ Log.d(TAG, "onExpansionFromPulseStopped");
+ }
+ // TODO: maybe add event
+ }
+
public void onNotificatonStopDraggingDown() {
if (DEBUG) {
Log.d(TAG, "onNotificationStopDraggingDown");
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 909896e..f8856ce 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -32,6 +32,7 @@
public static final int RIGHT_AFFORDANCE = 6;
public static final int GENERIC = 7;
public static final int BOUNCER_UNLOCK = 8;
+ public static final int PULSE_EXPAND = 9;
/**
* Contains all the information about touch events from which the classifier can query
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
index 5f04222..78b4168 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -22,6 +22,7 @@
boolean vertical = Math.abs(yDiff) >= Math.abs(xDiff);
switch (type) {
case Classifier.QUICK_SETTINGS:
+ case Classifier.PULSE_EXPAND:
case Classifier.NOTIFICATION_DRAG_DOWN:
if (!vertical || yDiff <= 0.0) {
return falsingEvaluation;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 8f215ff..a63fdbd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -408,10 +408,22 @@
mDataCollector.onNotificatonStartDraggingDown();
}
+ public void onStartExpandingFromPulse() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onStartExpandingFromPulse", "");
+ }
+ mHumanInteractionClassifier.setType(Classifier.PULSE_EXPAND);
+ mDataCollector.onStartExpandingFromPulse();
+ }
+
public void onNotificatonStopDraggingDown() {
mDataCollector.onNotificatonStopDraggingDown();
}
+ public void onExpansionFromPulseStopped() {
+ mDataCollector.onExpansionFromPulseStopped();
+ }
+
public void onNotificationDismissed() {
mDataCollector.onNotificationDismissed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 577d57a..0cc50cd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -128,7 +128,8 @@
// sent to the classifiers until the finger moves far enough. When the finger if lifted
// up, the last MotionEvent which was far enough from the finger is set as the final
// MotionEvent and sent to the Classifiers.
- if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN) {
+ if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN
+ || mCurrentType == Classifier.PULSE_EXPAND) {
mBufferedEvents.add(MotionEvent.obtain(event));
Point pointEnd = new Point(event.getX() / mDpi, event.getY() / mDpi);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
new file mode 100644
index 0000000..f318c54
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.os.PowerManager
+import android.os.PowerManager.WAKE_REASON_GESTURE
+import android.os.SystemClock
+import android.view.MotionEvent
+import android.view.ViewConfiguration
+
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+import com.android.systemui.classifier.FalsingManager
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.phone.ShadeController
+
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlin.math.max
+
+/**
+ * A utility class to enable the downward swipe on when pulsing.
+ */
+@Singleton
+class PulseExpansionHandler @Inject
+constructor(context: Context,
+ private val mWakeUpCoordinator: NotificationWakeUpCoordinator,
+ private val mAmbientPulseManager: AmbientPulseManager) : Gefingerpoken {
+ private val mPowerManager: PowerManager?
+ private var mShadeController: ShadeController? = null
+
+ private val mMinDragDistance: Int
+ private var mInitialTouchX: Float = 0.0f
+ private var mInitialTouchY: Float = 0.0f
+ var isExpanding: Boolean = false
+ private set
+ private val mTouchSlop: Float
+ private var mExpansionCallback: ExpansionCallback? = null
+ private lateinit var mStackScroller: NotificationStackScrollLayout
+ private val mTemp2 = IntArray(2)
+ private var mDraggedFarEnough: Boolean = false
+ private var mStartingChild: ExpandableView? = null
+ private val mFalsingManager: FalsingManager
+ private var mPulsing: Boolean = false
+ var isWakingToShadeLocked: Boolean = false
+ private set
+ private var mEmptyDragAmount: Float = 0.0f
+ private var mWakeUpHeight: Float = 0.0f
+ private var mReachedWakeUpHeight: Boolean = false
+
+ private val isFalseTouch: Boolean
+ get() = mFalsingManager.isFalseTouch
+
+ init {
+ mMinDragDistance = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance)
+ mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
+ mFalsingManager = FalsingManager.getInstance(context)
+ mPowerManager = context.getSystemService(PowerManager::class.java)
+ }
+
+ override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
+ return maybeStartExpansion(event)
+ }
+
+ private fun maybeStartExpansion(event: MotionEvent): Boolean {
+ if (!mPulsing) {
+ return false
+ }
+ val x = event.x
+ val y = event.y
+
+ when (event.actionMasked) {
+ MotionEvent.ACTION_DOWN -> {
+ mDraggedFarEnough = false
+ isExpanding = false
+ mStartingChild = null
+ mInitialTouchY = y
+ mInitialTouchX = x
+ }
+
+ MotionEvent.ACTION_MOVE -> {
+ val h = y - mInitialTouchY
+ if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ mFalsingManager.onStartExpandingFromPulse()
+ isExpanding = true
+ captureStartingChild(mInitialTouchX, mInitialTouchY)
+ mInitialTouchY = y
+ mInitialTouchX = x
+ mWakeUpHeight = mWakeUpCoordinator.getWakeUpHeight()
+ mReachedWakeUpHeight = false
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (!isExpanding) {
+ return maybeStartExpansion(event)
+ }
+ val y = event.y
+
+ when (event.actionMasked) {
+ MotionEvent.ACTION_MOVE -> updateExpansionHeight(y - mInitialTouchY)
+ MotionEvent.ACTION_UP -> if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch) {
+ finishExpansion()
+ } else {
+ cancelExpansion()
+ }
+ MotionEvent.ACTION_CANCEL -> cancelExpansion()
+ }
+ return isExpanding
+ }
+
+ private fun finishExpansion() {
+ resetClock()
+ if (mStartingChild != null) {
+ setUserLocked(mStartingChild!!, false)
+ mStartingChild = null
+ }
+ isExpanding = false
+ isWakingToShadeLocked = true
+ mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
+ "com.android.systemui:PULSEDRAG")
+ mShadeController!!.goToLockedShade(mStartingChild)
+ if (mStartingChild is ExpandableNotificationRow) {
+ val row = mStartingChild as ExpandableNotificationRow?
+ row!!.onExpandedByGesture(true /* userExpanded */)
+ }
+ }
+
+ private fun updateExpansionHeight(height: Float) {
+ var expansionHeight = max(height, 0.0f)
+ if (!mReachedWakeUpHeight && height > mWakeUpHeight) {
+ mReachedWakeUpHeight = true;
+ }
+ if (mStartingChild != null) {
+ val child = mStartingChild!!
+ val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(),
+ child.maxContentHeight)
+ child.actualHeight = newHeight
+ expansionHeight = max(newHeight.toFloat(), expansionHeight)
+ } else {
+ if (!mAmbientPulseManager.hasNotifications()) {
+ // No pulsing notifications, we need to make notifications visible
+ val target = if (mReachedWakeUpHeight) (mWakeUpHeight / 2.0f) else 0.0f
+
+ mWakeUpCoordinator.setNotificationsVisible(height > target, true /* animate */,
+ true /* increaseSpeed */)
+ }
+ expansionHeight = max(mWakeUpHeight, expansionHeight)
+ }
+ val emptyDragAmount = mWakeUpCoordinator.setPulseWakeUpHeight(expansionHeight)
+ setEmptyDragAmount(emptyDragAmount * RUBBERBAND_FACTOR_STATIC)
+ }
+
+ private fun captureStartingChild(x: Float, y: Float) {
+ if (mStartingChild == null) {
+ mStartingChild = findView(x, y)
+ if (mStartingChild != null) {
+ setUserLocked(mStartingChild!!, true)
+ }
+ }
+ }
+
+ private fun setEmptyDragAmount(amount: Float) {
+ mEmptyDragAmount = amount
+ mExpansionCallback!!.setEmptyDragAmount(amount)
+ }
+
+ private fun reset(child: ExpandableView) {
+ if (child.actualHeight == child.collapsedHeight) {
+ setUserLocked(child, false)
+ return
+ }
+ val anim = ObjectAnimator.ofInt(child, "actualHeight",
+ child.actualHeight, child.collapsedHeight)
+ anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+ anim.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ setUserLocked(child, false)
+ }
+ })
+ anim.start()
+ }
+
+ private fun setUserLocked(child: ExpandableView, userLocked: Boolean) {
+ if (child is ExpandableNotificationRow) {
+ child.isUserLocked = userLocked
+ }
+ }
+
+ private fun resetClock() {
+ val anim = ValueAnimator.ofFloat(mEmptyDragAmount, 0f)
+ anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
+ anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+ anim.addUpdateListener { animation -> setEmptyDragAmount(animation.animatedValue as Float) }
+ anim.start()
+ }
+
+ private fun cancelExpansion() {
+ mFalsingManager.onExpansionFromPulseStopped()
+ if (mStartingChild != null) {
+ reset(mStartingChild!!)
+ mStartingChild = null
+ } else {
+ resetClock()
+ }
+ if (!mAmbientPulseManager.hasNotifications()) {
+ mWakeUpCoordinator.setNotificationsVisible(false /* visible */, true /* animate */,
+ false /* increaseSpeed */)
+ }
+ isExpanding = false
+ }
+
+ private fun findView(x: Float, y: Float): ExpandableView? {
+ var totalX = x
+ var totalY = y
+ mStackScroller.getLocationOnScreen(mTemp2)
+ totalX += mTemp2[0].toFloat()
+ totalY += mTemp2[1].toFloat()
+ val childAtRawPosition = mStackScroller.getChildAtRawPosition(totalX, totalY)
+ return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) {
+ childAtRawPosition
+ } else null
+ }
+
+ fun setUp(notificationStackScroller: NotificationStackScrollLayout,
+ expansionCallback: ExpansionCallback,
+ shadeController: ShadeController) {
+ mExpansionCallback = expansionCallback
+ mShadeController = shadeController
+ mStackScroller = notificationStackScroller
+ }
+
+ fun setPulsing(pulsing: Boolean) {
+ mPulsing = pulsing
+ val hasAmbientNotifications = mAmbientPulseManager.hasNotifications();
+ if (pulsing && hasAmbientNotifications) {
+ mWakeUpCoordinator.setNotificationsVisible(true /* visible */, true /* animate */,
+ false /* increaseSpeed */)
+ } else if (!pulsing && !hasAmbientNotifications) {
+ // TODO: figure out the optimal UX for this, should we extend the pulse instead?
+ mWakeUpCoordinator.setNotificationsVisible(false /* visible */, true /* animate */,
+ false /* increaseSpeed */)
+ }
+ }
+
+ fun onStartedWakingUp() {
+ isWakingToShadeLocked = false
+ }
+
+ interface ExpansionCallback {
+ fun setEmptyDragAmount(amount: Float)
+ }
+
+ companion object {
+ private val RUBBERBAND_FACTOR_STATIC = 0.25f
+
+ private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index f3c8e6f..1ea3bb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -55,37 +55,47 @@
mStackScroller = stackScroller
}
- fun setNotificationsVisible(visible: Boolean, animate: Boolean) {
+ /**
+ * @param visible should notifications be visible
+ * @param animate should this change be animated
+ * @param increaseSpeed should the speed be increased of the animation
+ */
+ fun setNotificationsVisible(visible: Boolean, animate: Boolean, increaseSpeed: Boolean) {
if (mNotificationsVisible == visible) {
return
}
mNotificationsVisible = visible
mDarkAnimator?.cancel();
if (animate) {
- startVisibilityAnimation()
notifyAnimationStart(visible)
+ startVisibilityAnimation(increaseSpeed)
} else {
setVisibilityAmount(if (visible) 1.0f else 0.0f)
}
}
fun setDozeAmount(linearAmount: Float, interpolatedAmount: Float) {
- mLinearDozeAmount = linearAmount;
- mDozeAmount = interpolatedAmount;
+ mLinearDozeAmount = linearAmount
+ mDozeAmount = interpolatedAmount
+ mStackScroller.setDozeAmount(mDozeAmount)
updateDarkAmount()
}
- private fun startVisibilityAnimation() {
+ private fun startVisibilityAnimation(increaseSpeed: Boolean) {
if (mNotificationVisibleAmount == 0f || mNotificationVisibleAmount == 1f) {
mVisibilityInterpolator = if (mNotificationsVisible)
- Interpolators.TOUCH_RESPONSE_REVERSE
+ Interpolators.TOUCH_RESPONSE
else
- Interpolators.FAST_OUT_SLOW_IN
+ Interpolators.FAST_OUT_SLOW_IN_REVERSE
}
val target = if (mNotificationsVisible) 1.0f else 0.0f
val darkAnimator = ObjectAnimator.ofFloat(this, mNotificationVisibility, target)
darkAnimator.setInterpolator(Interpolators.LINEAR)
- darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong())
+ var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
+ if (increaseSpeed) {
+ duration = (duration.toFloat() / 1.5F).toLong();
+ }
+ darkAnimator.setDuration(duration)
darkAnimator.start()
mDarkAnimator = darkAnimator
}
@@ -97,13 +107,30 @@
updateDarkAmount()
}
+ fun getWakeUpHeight() : Float {
+ return mStackScroller.wakeUpHeight
+ }
+
private fun updateDarkAmount() {
val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
mStackScroller.setDarkAmount(linearAmount, amount)
}
- fun notifyAnimationStart(awake: Boolean) {
+ private fun notifyAnimationStart(awake: Boolean) {
mStackScroller.notifyDarkAnimationStart(!awake)
}
+
+ fun setDozing(dozing: Boolean, animate: Boolean) {
+ if (dozing) {
+ setNotificationsVisible(false /* animate */, false, true /* visible */ )
+ }
+ if (animate) {
+ notifyAnimationStart(!dozing)
+ }
+ }
+
+ fun setPulseWakeUpHeight(height: Float): Float {
+ return mStackScroller.setPulseWakeUpHeight(height)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 646617c..3cc2e83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -793,11 +793,11 @@
}
public int getMaxHeight() {
- if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
- return getShowingAmbientView().getHeight();
- } else if (mExpandedChild != null) {
+ if (mExpandedChild != null) {
return getViewHeight(VISIBLE_TYPE_EXPANDED)
+ getExtraRemoteInputHeight(mExpandedRemoteInput);
+ } else if (mContainingNotification.isOnAmbient() && getShowingAmbientView() != null) {
+ return getShowingAmbientView().getHeight();
} else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
return getViewHeight(VISIBLE_TYPE_HEADSUP)
+ getExtraRemoteInputHeight(mHeadsUpRemoteInput);
@@ -1113,15 +1113,6 @@
* @return one of the static enum types in this view, calculated form the current state
*/
public int calculateVisibleType() {
- if (mContainingNotification.isOnAmbient()) {
- if (mIsChildInGroup && mAmbientSingleLineChild != null) {
- return VISIBLE_TYPE_AMBIENT_SINGLELINE;
- } else if (mAmbientChild != null) {
- return VISIBLE_TYPE_AMBIENT;
- } else {
- return VISIBLE_TYPE_CONTRACTED;
- }
- }
if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded()
|| mContainingNotification.isExpanded(true /* allowOnKeyguard */)
@@ -1152,8 +1143,10 @@
if (!noExpandedChild && viewHeight == getViewHeight(VISIBLE_TYPE_EXPANDED)) {
return VISIBLE_TYPE_EXPANDED;
}
+ boolean onAmbient = mContainingNotification.isOnAmbient();
if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) {
- return VISIBLE_TYPE_SINGLELINE;
+ return onAmbient ? VISIBLE_TYPE_AMBIENT_SINGLELINE
+ : VISIBLE_TYPE_SINGLELINE;
}
if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null
@@ -1164,11 +1157,13 @@
return VISIBLE_TYPE_EXPANDED;
}
} else {
+ int collapsedType = onAmbient && mAmbientChild != null ? VISIBLE_TYPE_AMBIENT :
+ VISIBLE_TYPE_CONTRACTED;
if (noExpandedChild || (mContractedChild != null
- && viewHeight <= getViewHeight(VISIBLE_TYPE_CONTRACTED)
+ && viewHeight <= getViewHeight(collapsedType)
&& (!mIsChildInGroup || isGroupExpanded()
|| !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
- return VISIBLE_TYPE_CONTRACTED;
+ return collapsedType;
} else {
return VISIBLE_TYPE_EXPANDED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index c246af5..cb066f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.util.MathUtils;
import android.view.View;
import com.android.systemui.Dependency;
@@ -79,6 +80,8 @@
private ExpandableNotificationRow mExpandingNotification;
private float mDarkAmount;
private boolean mAppearing;
+ private float mPulseWakeUpHeight = Float.MAX_VALUE;
+ private float mDozeAmount = 0.0f;
public AmbientState(Context context) {
mSectionBoundaryIndices.add(NO_SECTION_BOUNDARY);
@@ -279,7 +282,21 @@
}
public int getInnerHeight() {
- return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
+ return getInnerHeight(false /* ignorePulseHeight */);
+ }
+
+ /**
+ * @param ignorePulseHeight ignore the pulse height for this request
+ * @return the inner height of the algorithm.
+ */
+ public int getInnerHeight(boolean ignorePulseHeight) {
+ int height = Math.max(mLayoutMinHeight,
+ Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding);
+ if (ignorePulseHeight) {
+ return height;
+ }
+ float pulseHeight = Math.min(mPulseWakeUpHeight, (float) height);
+ return (int) MathUtils.lerp(height, pulseHeight, mDozeAmount);
}
public boolean isShadeExpanded() {
@@ -488,4 +505,17 @@
public boolean isAppearing() {
return mAppearing;
}
+
+ public void setPulseWakeUpHeight(float height) {
+ mPulseWakeUpHeight = height;
+ }
+
+ public void setDozeAmount(float dozeAmount) {
+ if (dozeAmount != mDozeAmount) {
+ mDozeAmount = dozeAmount;
+ if (dozeAmount == 0.0f || dozeAmount == 1.0f) {
+ mPulseWakeUpHeight = Float.MAX_VALUE;
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
index 507cf07..a471d87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationFilter.java
@@ -132,10 +132,6 @@
// to look nice
customDelay = StackStateAnimator.ANIMATION_DELAY_HEADS_UP_CLICKED
+ StackStateAnimator.ANIMATION_DELAY_HEADS_UP;
- } else if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_PULSE_APPEAR || ev.animationType ==
- NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
- customDelay = StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 4d69742..4bb8aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -88,6 +88,7 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -167,6 +168,7 @@
* gap is drawn between them). In this case we don't want to round their corners.
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
+ private final AmbientPulseManager mAmbientPulseManager;
private ExpandHelper mExpandHelper;
private final NotificationSwipeHelper mSwipeHelper;
@@ -392,7 +394,6 @@
private boolean mGroupExpandedForMeasure;
private boolean mScrollable;
private View mForcedScroll;
- private ExpandableView mNeedingPulseAnimation;
/**
* @see #setDarkAmount(float, float)
@@ -481,7 +482,8 @@
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
- NotificationRoundnessManager notificationRoundnessManager) {
+ NotificationRoundnessManager notificationRoundnessManager,
+ AmbientPulseManager ambientPulseManager) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -491,6 +493,7 @@
mSections[i] = new NotificationSection(this);
}
+ mAmbientPulseManager = ambientPulseManager;
mAmbientState = new AmbientState(context);
mRoundnessManager = notificationRoundnessManager;
mBgColor = context.getColor(R.color.notification_shade_background_color);
@@ -575,6 +578,14 @@
}
}
+ public float getWakeUpHeight() {
+ ActivatableNotificationView firstChild = getFirstChildWithBackground();
+ if (firstChild != null) {
+ return firstChild.getCollapsedHeight();
+ }
+ return 0;
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onDensityOrFontScaleChanged() {
@@ -1277,7 +1288,8 @@
mIsClipped = clipped;
}
- if (mPulsing || mAmbientState.isFullyDark() && mShowDarkShelf) {
+ if (!mAmbientPulseManager.hasNotifications()
+ && mAmbientState.isFullyDark() && mShowDarkShelf) {
setClipBounds(null);
} else if (mAmbientState.isDarkAtAll()) {
setClipBounds(mBackgroundAnimationRect);
@@ -1514,7 +1526,7 @@
return null;
}
- private ExpandableView getChildAtRawPosition(float touchX, float touchY) {
+ public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
}
@@ -3354,7 +3366,6 @@
generateViewResizeEvent();
generateGroupExpansionEvent();
generateAnimateEverythingEvent();
- generatePulsingAnimationEvent();
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4354,10 +4365,12 @@
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public void setIsExpanded(boolean isExpanded) {
+ private void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
mStackScrollAlgorithm.setIsExpanded(isExpanded);
+ mAmbientState.setShadeExpanded(isExpanded);
+ mStateAnimator.setShadeExpanded(isExpanded);
if (changed) {
if (!mIsExpanded) {
mGroupManager.collapseAllGroups();
@@ -5099,12 +5112,6 @@
}
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setShadeExpanded(boolean shadeExpanded) {
- mAmbientState.setShadeExpanded(shadeExpanded);
- mStateAnimator.setShadeExpanded(shadeExpanded);
- }
-
/**
* Set the boundary for the bottom heads up position. The heads up will always be above this
* position.
@@ -5166,24 +5173,12 @@
return;
}
mPulsing = pulsing;
- mNeedingPulseAnimation = animated ? getFirstChildNotGone() : null;
mAmbientState.setPulsing(pulsing);
updateNotificationAnimationStates();
updateAlgorithmHeightAndPadding();
updateContentHeight();
requestChildrenUpdate();
notifyHeightChangeListener(null, animated);
- mNeedsAnimation |= animated;
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void generatePulsingAnimationEvent() {
- if (mNeedingPulseAnimation != null) {
- int type = mPulsing ? AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR
- : AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR;
- mAnimationEvents.add(new AnimationEvent(mNeedingPulseAnimation, type));
- mNeedingPulseAnimation = null;
- }
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5626,6 +5621,27 @@
}
/**
+ * Set how far the wake up is when waking up from pulsing. This is a height and will adjust the
+ * notification positions accordingly.
+ * @param height the new wake up height
+ * @return the overflow how much the height is further than he lowest notification
+ */
+ public float setPulseWakeUpHeight(float height) {
+ mAmbientState.setPulseWakeUpHeight(height);
+ requestChildrenUpdate();
+ return Math.max(0, height - mAmbientState.getInnerHeight(true /* ignorePulseHeight */));
+ }
+
+ /**
+ * Set the amount how much we're dozing. This is different from how dark the shade is, when
+ * the notification is pulsing.
+ */
+ public void setDozeAmount(float dozeAmount) {
+ mAmbientState.setDozeAmount(dozeAmount);
+ requestChildrenUpdate();
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5861,18 +5877,6 @@
.animateTopInset()
.animateY()
.animateZ(),
-
- // ANIMATION_TYPE_PULSE_APPEAR
- new AnimationFilter()
- .animateAlpha()
- .hasDelays()
- .animateY(),
-
- // ANIMATION_TYPE_PULSE_DISAPPEAR
- new AnimationFilter()
- .animateAlpha()
- .hasDelays()
- .animateY(),
};
static int[] LENGTHS = new int[]{
@@ -5927,12 +5931,6 @@
// ANIMATION_TYPE_EVERYTHING
StackStateAnimator.ANIMATION_DURATION_STANDARD,
-
- // ANIMATION_TYPE_PULSE_APPEAR
- StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR,
-
- // ANIMATION_TYPE_PULSE_DISAPPEAR
- StackStateAnimator.ANIMATION_DURATION_PULSE_APPEAR / 2,
};
static final int ANIMATION_TYPE_ADD = 0;
@@ -5952,8 +5950,6 @@
static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 14;
static final int ANIMATION_TYPE_HEADS_UP_OTHER = 15;
static final int ANIMATION_TYPE_EVERYTHING = 16;
- static final int ANIMATION_TYPE_PULSE_APPEAR = 17;
- static final int ANIMATION_TYPE_PULSE_DISAPPEAR = 18;
static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index b4c205a..7332b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -419,32 +419,6 @@
ExpandableNotificationRow row = (ExpandableNotificationRow) event.mChangingView;
row.prepareExpansionChanged();
} else if (event.animationType == NotificationStackScrollLayout
- .AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR) {
- ExpandableViewState viewState = changingView.getViewState();
- if (viewState != null) {
- mTmpState.copyFrom(viewState);
- mTmpState.yTranslation += mPulsingAppearingTranslation;
- mTmpState.alpha = 0;
- mTmpState.applyToView(changingView);
-
- mTmpState.copyFrom(mShelf.getViewState());
- mTmpState.applyToView(mShelf);
- }
- } else if (event.animationType == NotificationStackScrollLayout
- .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
- ExpandableViewState viewState = changingView.getViewState();
- if (viewState != null) {
- viewState.alpha = 0;
- // We want to animate the alpha away before the view starts translating,
- // otherwise everything will overlap and look xtra ugly.
- float originalYTranslation = viewState.yTranslation;
- viewState.yTranslation = changingView.getTranslationY();
- mAnimationFilter.animateAlpha = true;
- mAnimationProperties.duration = ANIMATION_DURATION_PULSE_APPEAR / 2;
- viewState.animateTo(changingView, mAnimationProperties);
- viewState.yTranslation = originalYTranslation;
- }
- } else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
// This item is added, initialize it's properties.
ExpandableViewState viewState = changingView.getViewState();
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 ce4d95f..4398ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,6 +18,7 @@
import static com.android.systemui.SysUiServiceProvider.getComponent;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
@@ -75,6 +76,7 @@
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -108,7 +110,8 @@
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback,
- ConfigurationController.ConfigurationListener, StateListener {
+ ConfigurationController.ConfigurationListener, StateListener,
+ PulseExpansionHandler.ExpansionCallback {
private static final boolean DEBUG = false;
@@ -144,6 +147,7 @@
private final PowerManager mPowerManager;
private final AccessibilityManager mAccessibilityManager;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
+ private final PulseExpansionHandler mPulseExpansionHandler;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -327,7 +331,8 @@
@Inject
public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- NotificationWakeUpCoordinator coordinator) {
+ NotificationWakeUpCoordinator coordinator,
+ PulseExpansionHandler pulseExpansionHandler) {
super(context, attrs);
setWillNotDraw(!DEBUG);
mFalsingManager = FalsingManager.getInstance(context);
@@ -339,6 +344,7 @@
setPanelAlpha(255, false /* animate */);
mCommandQueue = getComponent(context, CommandQueue.class);
mDisplayId = context.getDisplayId();
+ mPulseExpansionHandler = pulseExpansionHandler;
}
/**
@@ -377,6 +383,7 @@
mWakeUpCoordinator.setStackScroller(mNotificationStackScroller);
mQsFrame = findViewById(R.id.qs_frame);
+ mPulseExpansionHandler.setUp(mNotificationStackScroller, this, mShadeController);
}
@Override
@@ -798,6 +805,9 @@
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
return true;
}
+ if (mPulseExpansionHandler.onInterceptTouchEvent(event)) {
+ return true;
+ }
if (!isFullyCollapsed() && onQsIntercept(event)) {
return true;
@@ -957,6 +967,10 @@
return false;
}
initDownStates(event);
+ if (!mIsExpanding && mPulseExpansionHandler.onTouchEvent(event)) {
+ // We're expanding all the other ones shouldn't get this anymore
+ return true;
+ }
if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
&& mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
mIsExpansionFromHeadsUp = true;
@@ -1500,16 +1514,16 @@
int max = mBarState == StatusBarState.KEYGUARD
? Math.max(maxNotificationPadding, maxQsPadding)
: maxQsPadding;
- return (int) interpolate(getExpandedFraction(),
- mQsMinExpansionHeight, max);
+ return (int) MathUtils.lerp((float) mQsMinExpansionHeight, (float) max,
+ getExpandedFraction());
} else if (mQsSizeChangeAnimator != null) {
return (int) mQsSizeChangeAnimator.getAnimatedValue();
} else if (mKeyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
- return interpolate(getQsExpansionFraction(),
- mNotificationStackScroller.getIntrinsicPadding(),
- mQsMaxExpansionHeight + mQsNotificationTopPadding);
+ return MathUtils.lerp((float) mNotificationStackScroller.getIntrinsicPadding(),
+ (float) (mQsMaxExpansionHeight + mQsNotificationTopPadding),
+ getQsExpansionFraction());
} else {
return mQsExpansionHeight + mQsNotificationTopPadding;
}
@@ -1710,7 +1724,6 @@
updateUnlockIcon();
updateNotificationTranslucency();
updatePanelExpanded();
- mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
if (DEBUG) {
invalidate();
}
@@ -2824,9 +2837,7 @@
final float darkAmount = dozing ? 1 : 0;
mStatusBarStateController.setDozeAmount(darkAmount, animate);
- if (animate) {
- mWakeUpCoordinator.notifyAnimationStart(!mDozing);
- }
+ mWakeUpCoordinator.setDozing(mDozing, animate);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 41580f6..a1560bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -184,6 +184,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -363,6 +364,8 @@
protected StatusBarIconController mIconController;
@Inject
InjectionInflationController mInjectionInflater;
+ @Inject
+ PulseExpansionHandler mPulseExpansionHandler;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -1079,7 +1082,7 @@
@Override
public boolean isDozing() {
- return mDozing && mNotificationPanel.isFullyDark();
+ return mDozing;
}
@Override
@@ -2965,7 +2968,7 @@
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER);
- } else {
+ } else if (!mPulseExpansionHandler.isWakingToShadeLocked()){
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
updatePanelExpansionForKeyguard();
@@ -3594,6 +3597,7 @@
updateVisibleToUser();
updateIsKeyguard();
mDozeServiceHost.stopDozing();
+ mPulseExpansionHandler.onStartedWakingUp();
}
};
@@ -3896,6 +3900,7 @@
mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
}
updateScrimController();
+ mPulseExpansionHandler.setPulsing(pulsing);
}
}, reason);
// DozeScrimController is in pulse state, now let's ask ScrimController to start
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 50c4fac..a8ae5f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -388,7 +388,8 @@
if (mNotificationPanel.isFullyExpanded()
&& stackScrollLayout.getVisibility() == View.VISIBLE
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && !mService.isBouncerShowing()) {
+ && !mService.isBouncerShowing()
+ && !mService.isDozing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {