Merge "Fix HUN launch animation" into sc-dev

This commit is contained in:
Jordan Demeulenaere
2021-06-08 09:28:10 +00:00
committed by Android (Google) Code Review
8 changed files with 138 additions and 20 deletions

View File

@@ -204,6 +204,12 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
return; return;
} }
NotificationEntry entry = alertEntry.mEntry; NotificationEntry entry = alertEntry.mEntry;
// If the notification is animating, we will remove it at the end of the animation.
if (entry != null && entry.isExpandAnimationRunning()) {
return;
}
mAlertEntries.remove(key); mAlertEntries.remove(key);
onAlertEntryRemoved(alertEntry); onAlertEntryRemoved(alertEntry);
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);

View File

@@ -7,6 +7,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
import com.android.systemui.statusbar.policy.HeadsUpUtil
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@@ -22,8 +23,8 @@ class NotificationLaunchAnimatorControllerProvider(
return NotificationLaunchAnimatorController( return NotificationLaunchAnimatorController(
notificationShadeWindowViewController, notificationShadeWindowViewController,
notificationListContainer, notificationListContainer,
notification, headsUpManager,
headsUpManager notification
) )
} }
} }
@@ -36,10 +37,11 @@ class NotificationLaunchAnimatorControllerProvider(
class NotificationLaunchAnimatorController( class NotificationLaunchAnimatorController(
private val notificationShadeWindowViewController: NotificationShadeWindowViewController, private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
private val notificationListContainer: NotificationListContainer, private val notificationListContainer: NotificationListContainer,
private val notification: ExpandableNotificationRow, private val headsUpManager: HeadsUpManagerPhone,
private val headsUpManager: HeadsUpManagerPhone private val notification: ExpandableNotificationRow
) : ActivityLaunchAnimator.Controller { ) : ActivityLaunchAnimator.Controller {
private val notificationKey = notification.entry.sbn.key private val notificationEntry = notification.entry
private val notificationKey = notificationEntry.sbn.key
override var launchContainer: ViewGroup override var launchContainer: ViewGroup
get() = notification.rootView as ViewGroup get() = notification.rootView as ViewGroup
@@ -82,6 +84,7 @@ class NotificationLaunchAnimatorController(
override fun onIntentStarted(willAnimate: Boolean) { override fun onIntentStarted(willAnimate: Boolean) {
notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate) notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate)
notificationEntry.isExpandAnimationRunning = willAnimate
if (!willAnimate) { if (!willAnimate) {
removeHun(animate = true) removeHun(animate = true)
@@ -93,6 +96,7 @@ class NotificationLaunchAnimatorController(
return return
} }
HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(notification, animate)
headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate) headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate)
} }
@@ -100,6 +104,7 @@ class NotificationLaunchAnimatorController(
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here? // here?
notificationShadeWindowViewController.setExpandAnimationRunning(false) notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true) removeHun(animate = true)
} }
@@ -116,6 +121,7 @@ class NotificationLaunchAnimatorController(
notification.isExpandAnimationRunning = false notification.isExpandAnimationRunning = false
notificationShadeWindowViewController.setExpandAnimationRunning(false) notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
notificationListContainer.setExpandingNotification(null) notificationListContainer.setExpandingNotification(null)
applyParams(null) applyParams(null)
removeHun(animate = false) removeHun(animate = false)

View File

@@ -179,6 +179,7 @@ public final class NotificationEntry extends ListEntry {
private boolean mIsAlerting; private boolean mIsAlerting;
public boolean mRemoteEditImeVisible; public boolean mRemoteEditImeVisible;
private boolean mExpandAnimationRunning;
/** /**
* @param sbn the StatusBarNotification from system server * @param sbn the StatusBarNotification from system server
@@ -952,6 +953,16 @@ public final class NotificationEntry extends ListEntry {
return mIsAlerting; return mIsAlerting;
} }
/** Set whether this notification is currently used to animate a launch. */
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
mExpandAnimationRunning = expandAnimationRunning;
}
/** Whether this notification is currently used to animate a launch. */
public boolean isExpandAnimationRunning() {
return mExpandAnimationRunning;
}
/** Information about a suggestion that is being edited. */ /** Information about a suggestion that is being edited. */
public static class EditedSuggestionInfo { public static class EditedSuggestionInfo {

View File

@@ -591,7 +591,7 @@ public class ViewState implements Dumpable {
animator.addListener(new AnimatorListenerAdapter() { animator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
HeadsUpUtil.setIsClickedHeadsUpNotification(child, false); HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(child, false);
child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null); child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
child.setTag(TAG_START_TRANSLATION_Y, null); child.setTag(TAG_START_TRANSLATION_Y, null);
child.setTag(TAG_END_TRANSLATION_Y, null); child.setTag(TAG_END_TRANSLATION_Y, null);

View File

@@ -28,8 +28,8 @@ class StatusBarLaunchAnimatorController(
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationEnd(isExpandingFullyAbove) delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
statusBar.onLaunchAnimationEnd(isExpandingFullyAbove)
statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(false) statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(false)
statusBar.onLaunchAnimationEnd(isExpandingFullyAbove)
} }
override fun onLaunchAnimationProgress( override fun onLaunchAnimationProgress(

View File

@@ -282,15 +282,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
boolean showOverLockscreen) { boolean showOverLockscreen) {
mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey()); mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
// TODO: Some of this code may be able to move to NotificationEntryManager.
String key = row.getEntry().getSbn().getKey();
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
// Release the HUN notification to the shade.
if (mPresenter.isPresenterFullyCollapsed()) {
HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
}
}
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed( final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
entry, row, controller, intent, entry, row, controller, intent,
isActivityIntent, animate); isActivityIntent, animate);
@@ -337,7 +328,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
// bypass work challenge // bypass work challenge
if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId, if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
intent.getIntentSender(), notificationKey)) { intent.getIntentSender(), notificationKey)) {
removeHUN(row); removeHunAfterClick(row);
// Show work challenge, do not run PendingIntent and // Show work challenge, do not run PendingIntent and
// remove notification // remove notification
collapseOnMainThread(); collapseOnMainThread();
@@ -357,7 +348,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
final boolean canBubble = entry.canBubble(); final boolean canBubble = entry.canBubble();
if (canBubble) { if (canBubble) {
mLogger.logExpandingBubble(notificationKey); mLogger.logExpandingBubble(notificationKey);
removeHUN(row); removeHunAfterClick(row);
expandBubbleStackOnMainThread(entry); expandBubbleStackOnMainThread(entry);
} else { } else {
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent); startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
@@ -508,9 +499,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}, null, false /* afterKeyguardGone */); }, null, false /* afterKeyguardGone */);
} }
private void removeHUN(ExpandableNotificationRow row) { private void removeHunAfterClick(ExpandableNotificationRow row) {
String key = row.getEntry().getSbn().getKey(); String key = row.getEntry().getSbn().getKey();
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) { if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
// Release the HUN notification to the shade.
if (mPresenter.isPresenterFullyCollapsed()) {
HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(row, true);
}
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
// become canceled shortly by NoMan, but we can't assume that. // become canceled shortly by NoMan, but we can't assume that.
mHeadsUpManager.removeNotification(key, true /* releaseImmediately */); mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);

View File

@@ -31,7 +31,7 @@ public final class HeadsUpUtil {
* @param view The view to be set the flag to. * @param view The view to be set the flag to.
* @param clicked True to set as clicked. False to not-clicked. * @param clicked True to set as clicked. False to not-clicked.
*/ */
public static void setIsClickedHeadsUpNotification(View view, boolean clicked) { public static void setNeedsHeadsUpDisappearAnimationAfterClick(View view, boolean clicked) {
view.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null); view.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
} }

View File

@@ -0,0 +1,99 @@
package com.android.systemui.statusbar.notification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
import com.android.systemui.statusbar.policy.HeadsUpUtil
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
class NotificationLaunchAnimatorControllerTest : SysuiTestCase() {
@Mock lateinit var notificationShadeWindowViewController: NotificationShadeWindowViewController
@Mock lateinit var notificationListContainer: NotificationListContainer
@Mock lateinit var headsUpManager: HeadsUpManagerPhone
private lateinit var notificationTestHelper: NotificationTestHelper
private lateinit var notification: ExpandableNotificationRow
private lateinit var controller: NotificationLaunchAnimatorController
private val notificationKey: String
get() = notification.entry.sbn.key
@get:Rule val rule = MockitoJUnit.rule()
@Before
fun setUp() {
allowTestableLooperAsMainThread()
notificationTestHelper =
NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
notification = notificationTestHelper.createRow()
controller = NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
notificationListContainer,
headsUpManager,
notification
)
}
private fun flagNotificationAsHun() {
`when`(headsUpManager.isAlerting(notificationKey)).thenReturn(true)
}
@Test
fun testHunIsRemovedIfWeDontAnimateLaunch() {
flagNotificationAsHun()
controller.onIntentStarted(willAnimate = false)
assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
}
@Test
fun testHunIsRemovedWhenAnimationIsCancelled() {
flagNotificationAsHun()
controller.onLaunchAnimationCancelled()
assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, true /* animate */)
}
@Test
fun testHunIsRemovedWhenAnimationEnds() {
flagNotificationAsHun()
controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
assertFalse(HeadsUpUtil.isClickedHeadsUpNotification(notification))
assertFalse(notification.entry.isExpandAnimationRunning)
verify(headsUpManager).removeNotification(
notificationKey, true /* releaseImmediately */, false /* animate */)
}
@Test
fun testNotificationIsExpandingDuringAnimation() {
controller.onIntentStarted(willAnimate = true)
assertTrue(notification.entry.isExpandAnimationRunning)
}
}