Merge "[Ongoing Call] Add an option to disable tapping the chip while in immersive mode." into sc-v2-dev

This commit is contained in:
Caitlin Cassidy
2021-10-12 18:10:22 +00:00
committed by Android (Google) Code Review
5 changed files with 120 additions and 30 deletions

View File

@@ -48,6 +48,8 @@
<bool name="flag_ongoing_call_in_immersive">false</bool> <bool name="flag_ongoing_call_in_immersive">false</bool>
<bool name="flag_ongoing_call_in_immersive_chip_tap">true</bool>
<bool name="flag_smartspace">false</bool> <bool name="flag_smartspace">false</bool>
<bool name="flag_smartspace_deduping">true</bool> <bool name="flag_smartspace_deduping">true</bool>

View File

@@ -166,6 +166,11 @@ public class FeatureFlags {
&& mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive); && mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive);
} }
public boolean isOngoingCallInImmersiveChipTapEnabled() {
return isOngoingCallInImmersiveEnabled()
&& mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive_chip_tap);
}
public boolean isSmartspaceEnabled() { public boolean isSmartspaceEnabled() {
return mFlagReader.isEnabled(R.bool.flag_smartspace); return mFlagReader.isEnabled(R.bool.flag_smartspace);
} }

View File

@@ -257,7 +257,8 @@ public interface StatusBarDependenciesModule {
OngoingCallLogger logger, OngoingCallLogger logger,
DumpManager dumpManager, DumpManager dumpManager,
StatusBarWindowController statusBarWindowController, StatusBarWindowController statusBarWindowController,
SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler) { SwipeStatusBarAwayGestureHandler swipeStatusBarAwayGestureHandler,
StatusBarStateController statusBarStateController) {
Optional<StatusBarWindowController> windowController = Optional<StatusBarWindowController> windowController =
featureFlags.isOngoingCallInImmersiveEnabled() featureFlags.isOngoingCallInImmersiveEnabled()
? Optional.of(statusBarWindowController) ? Optional.of(statusBarWindowController)
@@ -277,8 +278,8 @@ public interface StatusBarDependenciesModule {
logger, logger,
dumpManager, dumpManager,
windowController, windowController,
gestureHandler gestureHandler,
); statusBarStateController);
ongoingCallController.init(); ongoingCallController.init();
return ongoingCallController; return ongoingCallController;
} }

View File

@@ -34,6 +34,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -61,8 +62,10 @@ class OngoingCallController @Inject constructor(
private val dumpManager: DumpManager, private val dumpManager: DumpManager,
private val statusBarWindowController: Optional<StatusBarWindowController>, private val statusBarWindowController: Optional<StatusBarWindowController>,
private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>, private val swipeStatusBarAwayGestureHandler: Optional<SwipeStatusBarAwayGestureHandler>,
private val statusBarStateController: StatusBarStateController,
) : CallbackController<OngoingCallListener>, Dumpable { ) : CallbackController<OngoingCallListener>, Dumpable {
private var isFullscreen: Boolean = false
/** Non-null if there's an active call notification. */ /** Non-null if there's an active call notification. */
private var callNotificationInfo: CallNotificationInfo? = null private var callNotificationInfo: CallNotificationInfo? = null
/** True if the application managing the call is visible to the user. */ /** True if the application managing the call is visible to the user. */
@@ -124,6 +127,7 @@ class OngoingCallController @Inject constructor(
dumpManager.registerDumpable(this) dumpManager.registerDumpable(this)
if (featureFlags.isOngoingCallStatusBarChipEnabled) { if (featureFlags.isOngoingCallStatusBarChipEnabled) {
notifCollection.addCollectionListener(notifListener) notifCollection.addCollectionListener(notifListener)
statusBarStateController.addCallback(statusBarStateListener)
} }
} }
@@ -177,10 +181,8 @@ class OngoingCallController @Inject constructor(
val currentChipView = chipView val currentChipView = chipView
val timeView = currentChipView?.getTimeView() val timeView = currentChipView?.getTimeView()
val backgroundView =
currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
if (currentChipView != null && timeView != null && backgroundView != null) { if (currentChipView != null && timeView != null) {
if (currentCallNotificationInfo.hasValidStartTime()) { if (currentCallNotificationInfo.hasValidStartTime()) {
timeView.setShouldHideText(false) timeView.setShouldHideText(false)
timeView.base = currentCallNotificationInfo.callStartTime - timeView.base = currentCallNotificationInfo.callStartTime -
@@ -191,19 +193,8 @@ class OngoingCallController @Inject constructor(
timeView.setShouldHideText(true) timeView.setShouldHideText(true)
timeView.stop() timeView.stop()
} }
updateChipClickListener()
currentCallNotificationInfo.intent?.let { intent ->
currentChipView.setOnClickListener {
logger.logChipClicked()
activityStarter.postStartActivityDismissingKeyguard(
intent,
0,
ActivityLaunchAnimator.Controller.fromView(
backgroundView,
InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
)
}
}
setUpUidObserver(currentCallNotificationInfo) setUpUidObserver(currentCallNotificationInfo)
if (!currentCallNotificationInfo.statusBarSwipedAway) { if (!currentCallNotificationInfo.statusBarSwipedAway) {
statusBarWindowController.ifPresent { statusBarWindowController.ifPresent {
@@ -227,6 +218,30 @@ class OngoingCallController @Inject constructor(
} }
} }
private fun updateChipClickListener() {
if (callNotificationInfo == null) { return }
if (isFullscreen && !featureFlags.isOngoingCallInImmersiveChipTapEnabled) {
chipView?.setOnClickListener(null)
} else {
val currentChipView = chipView
val backgroundView =
currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
val intent = callNotificationInfo?.intent
if (currentChipView != null && backgroundView != null && intent != null) {
currentChipView.setOnClickListener {
logger.logChipClicked()
activityStarter.postStartActivityDismissingKeyguard(
intent,
0,
ActivityLaunchAnimator.Controller.fromView(
backgroundView,
InteractionJankMonitor.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP)
)
}
}
}
}
/** /**
* Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call. * Sets up an [IUidObserver] to monitor the status of the application managing the ongoing call.
*/ */
@@ -304,14 +319,21 @@ class OngoingCallController @Inject constructor(
* This method updates the status bar window appropriately when the swipe away gesture is * This method updates the status bar window appropriately when the swipe away gesture is
* detected. * detected.
*/ */
private fun onSwipeAwayGestureDetected() { private fun onSwipeAwayGestureDetected() {
if (DEBUG) { Log.d(TAG, "Swipe away gesture detected") } if (DEBUG) { Log.d(TAG, "Swipe away gesture detected") }
callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true) callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
statusBarWindowController.ifPresent { statusBarWindowController.ifPresent {
it.setOngoingProcessRequiresStatusBarVisible(false) it.setOngoingProcessRequiresStatusBarVisible(false)
} }
swipeStatusBarAwayGestureHandler.ifPresent { swipeStatusBarAwayGestureHandler.ifPresent {
it.removeOnGestureDetectedCallback(TAG) it.removeOnGestureDetectedCallback(TAG)
}
}
private val statusBarStateListener = object : StatusBarStateController.StateListener {
override fun onFullscreenStateChanged(isFullscreen: Boolean) {
this@OngoingCallController.isFullscreen = isFullscreen
updateChipClickListener()
} }
} }

View File

@@ -36,6 +36,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -82,11 +83,13 @@ class OngoingCallControllerTest : SysuiTestCase() {
private lateinit var controller: OngoingCallController private lateinit var controller: OngoingCallController
private lateinit var notifCollectionListener: NotifCollectionListener private lateinit var notifCollectionListener: NotifCollectionListener
@Mock private lateinit var mockFeatureFlags: FeatureFlags
@Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler @Mock private lateinit var mockSwipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler
@Mock private lateinit var mockOngoingCallListener: OngoingCallListener @Mock private lateinit var mockOngoingCallListener: OngoingCallListener
@Mock private lateinit var mockActivityStarter: ActivityStarter @Mock private lateinit var mockActivityStarter: ActivityStarter
@Mock private lateinit var mockIActivityManager: IActivityManager @Mock private lateinit var mockIActivityManager: IActivityManager
@Mock private lateinit var mockStatusBarWindowController: StatusBarWindowController @Mock private lateinit var mockStatusBarWindowController: StatusBarWindowController
@Mock private lateinit var mockStatusBarStateController: StatusBarStateController
private lateinit var chipView: View private lateinit var chipView: View
@@ -98,13 +101,12 @@ class OngoingCallControllerTest : SysuiTestCase() {
} }
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
val featureFlags = mock(FeatureFlags::class.java) `when`(mockFeatureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
`when`(featureFlags.isOngoingCallStatusBarChipEnabled).thenReturn(true)
val notificationCollection = mock(CommonNotifCollection::class.java) val notificationCollection = mock(CommonNotifCollection::class.java)
controller = OngoingCallController( controller = OngoingCallController(
notificationCollection, notificationCollection,
featureFlags, mockFeatureFlags,
clock, clock,
mockActivityStarter, mockActivityStarter,
mainExecutor, mainExecutor,
@@ -113,7 +115,8 @@ class OngoingCallControllerTest : SysuiTestCase() {
DumpManager(), DumpManager(),
Optional.of(mockStatusBarWindowController), Optional.of(mockStatusBarWindowController),
Optional.of(mockSwipeStatusBarAwayGestureHandler), Optional.of(mockSwipeStatusBarAwayGestureHandler),
) mockStatusBarStateController,
)
controller.init() controller.init()
controller.addCallback(mockOngoingCallListener) controller.addCallback(mockOngoingCallListener)
controller.setChipView(chipView) controller.setChipView(chipView)
@@ -455,6 +458,56 @@ class OngoingCallControllerTest : SysuiTestCase() {
// Other tests for notifyChipVisibilityChanged are in [OngoingCallLogger], since // Other tests for notifyChipVisibilityChanged are in [OngoingCallLogger], since
// [OngoingCallController.notifyChipVisibilityChanged] just delegates to that class. // [OngoingCallController.notifyChipVisibilityChanged] just delegates to that class.
@Test
fun callNotificationAdded_chipIsClickable() {
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
assertThat(chipView.hasOnClickListeners()).isTrue()
}
@Test
fun fullscreenIsTrue_thenCallNotificationAdded_chipNotClickable() {
`when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
assertThat(chipView.hasOnClickListeners()).isFalse()
}
@Test
fun callNotificationAdded_thenFullscreenIsTrue_chipNotClickable() {
`when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
assertThat(chipView.hasOnClickListeners()).isFalse()
}
@Test
fun fullscreenChangesToFalse_chipClickable() {
`when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(false)
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
// First, update to true
getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
// Then, update to false
getStateListener().onFullscreenStateChanged(/* isFullscreen= */ false)
assertThat(chipView.hasOnClickListeners()).isTrue()
}
@Test
fun fullscreenIsTrue_butChipClickInImmersiveEnabled_chipClickable() {
`when`(mockFeatureFlags.isOngoingCallInImmersiveChipTapEnabled).thenReturn(true)
notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
getStateListener().onFullscreenStateChanged(/* isFullscreen= */ true)
assertThat(chipView.hasOnClickListeners()).isTrue()
}
private fun createOngoingCallNotifEntry() = createCallNotifEntry(ongoingCallStyle) private fun createOngoingCallNotifEntry() = createCallNotifEntry(ongoingCallStyle)
private fun createScreeningCallNotifEntry() = createCallNotifEntry(screeningCallStyle) private fun createScreeningCallNotifEntry() = createCallNotifEntry(screeningCallStyle)
@@ -479,6 +532,13 @@ class OngoingCallControllerTest : SysuiTestCase() {
} }
private fun createNotCallNotifEntry() = NotificationEntryBuilder().build() private fun createNotCallNotifEntry() = NotificationEntryBuilder().build()
private fun getStateListener(): StatusBarStateController.StateListener {
val statusBarStateListenerCaptor = ArgumentCaptor.forClass(
StatusBarStateController.StateListener::class.java)
verify(mockStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture())
return statusBarStateListenerCaptor.value!!
}
} }
private val person = Person.Builder().setName("name").build() private val person = Person.Builder().setName("name").build()