Merge "Merge "Fix rendering issue after cancelling Notifications inside a group" into tm-qpr-dev am: ae41b142e8 am: 77dff21365"

This commit is contained in:
Automerger Merge Worker
2022-12-02 15:23:46 +00:00
committed by Android (Google) Code Review
3 changed files with 185 additions and 1 deletions

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import android.animation.Animator;
@@ -1404,6 +1405,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mKeepInParentForDismissAnimation = keepInParent;
}
/** @return true if the User has dismissed this notif's parent */
public boolean isParentDismissed() {
return getEntry().getDismissState() == PARENT_DISMISSED;
}
@Override
public boolean isRemoved() {
return mRemoved;

View File

@@ -359,10 +359,15 @@ public class ExpandableNotificationRowController implements NotifViewController
@Override
public boolean offerToKeepInParentForAnimation() {
if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)) {
//If the User dismissed the notification's parent, we want to keep it attached until the
//dismiss animation is ongoing. Therefore we don't want to remove it in the ShadeViewDiffer.
if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)
&& mView.isParentDismissed()) {
mView.setKeepInParentForDismissAnimation(true);
return true;
}
//Otherwise the view system doesn't do the removal, so we rely on the ShadeViewDiffer
return false;
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (c) 2022 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.notification.row
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.SmartReplyController
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.logging.NotificationLogger
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.SmartReplyConstants
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.SystemClock
import com.android.systemui.wmshell.BubblesManager
import java.util.Optional
import junit.framework.Assert
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.never
import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class ExpandableNotificationRowControllerTest : SysuiTestCase() {
private val appName = "MyApp"
private val notifKey = "MyNotifKey"
private val view: ExpandableNotificationRow = mock()
private val activableNotificationViewController: ActivatableNotificationViewController = mock()
private val rivSubComponentFactory: RemoteInputViewSubcomponent.Factory = mock()
private val metricsLogger: MetricsLogger = mock()
private val logBufferLogger: NotificationRowLogger = mock()
private val listContainer: NotificationListContainer = mock()
private val mediaManager: NotificationMediaManager = mock()
private val smartReplyConstants: SmartReplyConstants = mock()
private val smartReplyController: SmartReplyController = mock()
private val pluginManager: PluginManager = mock()
private val systemClock: SystemClock = mock()
private val keyguardBypassController: KeyguardBypassController = mock()
private val groupMembershipManager: GroupMembershipManager = mock()
private val groupExpansionManager: GroupExpansionManager = mock()
private val rowContentBindStage: RowContentBindStage = mock()
private val notifLogger: NotificationLogger = mock()
private val headsUpManager: HeadsUpManager = mock()
private val onExpandClickListener: ExpandableNotificationRow.OnExpandClickListener = mock()
private val statusBarStateController: StatusBarStateController = mock()
private val gutsManager: NotificationGutsManager = mock()
private val onUserInteractionCallback: OnUserInteractionCallback = mock()
private val falsingManager: FalsingManager = mock()
private val falsingCollector: FalsingCollector = mock()
private val featureFlags: FeatureFlags = mock()
private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
private val bubblesManager: BubblesManager = mock()
private val dragController: ExpandableNotificationRowDragController = mock()
private lateinit var controller: ExpandableNotificationRowController
@Before
fun setUp() {
allowTestableLooperAsMainThread()
controller =
ExpandableNotificationRowController(
view,
activableNotificationViewController,
rivSubComponentFactory,
metricsLogger,
logBufferLogger,
listContainer,
mediaManager,
smartReplyConstants,
smartReplyController,
pluginManager,
systemClock,
appName,
notifKey,
keyguardBypassController,
groupMembershipManager,
groupExpansionManager,
rowContentBindStage,
notifLogger,
headsUpManager,
onExpandClickListener,
statusBarStateController,
gutsManager,
/*allowLongPress=*/ false,
onUserInteractionCallback,
falsingManager,
falsingCollector,
featureFlags,
peopleNotificationIdentifier,
Optional.of(bubblesManager),
dragController
)
}
@After
fun tearDown() {
disallowTestableLooperAsMainThread()
}
@Test
fun offerKeepInParent_parentDismissed() {
whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
.thenReturn(true)
whenever(view.isParentDismissed).thenReturn(true)
Assert.assertTrue(controller.offerToKeepInParentForAnimation())
Mockito.verify(view).setKeepInParentForDismissAnimation(true)
}
@Test
fun offerKeepInParent_parentNotDismissed() {
whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
.thenReturn(true)
Assert.assertFalse(controller.offerToKeepInParentForAnimation())
Mockito.verify(view, never()).setKeepInParentForDismissAnimation(anyBoolean())
}
@Test
fun removeFromParent_keptForAnimation() {
val parentView: ExpandableNotificationRow = mock()
whenever(view.notificationParent).thenReturn(parentView)
whenever(view.keepInParentForDismissAnimation()).thenReturn(true)
Assert.assertTrue(controller.removeFromParentIfKeptForAnimation())
Mockito.verify(parentView).removeChildNotification(view)
}
@Test
fun removeFromParent_notKeptForAnimation() {
val parentView: ExpandableNotificationRow = mock()
whenever(view.notificationParent).thenReturn(parentView)
Assert.assertFalse(controller.removeFromParentIfKeptForAnimation())
Mockito.verifyNoMoreInteractions(parentView)
}
}