diff options
5 files changed, 112 insertions, 25 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt index 3562fd1e9134..ed1756aff8c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt @@ -55,25 +55,26 @@ constructor( when (state) { is OngoingCallModel.NoCall -> OngoingActivityChipModel.Hidden is OngoingCallModel.InCall -> { - // This mimics OngoingCallController#updateChip. - // TODO(b/332662551): Handle `state.startTimeMs = 0` correctly (see - // b/192379214 and - // OngoingCallController.CallNotificationInfo.hasValidStartTime). - val startTimeInElapsedRealtime = - state.startTimeMs - systemClock.currentTimeMillis() + - systemClock.elapsedRealtime() - OngoingActivityChipModel.Shown.Timer( - icon = - Icon.Resource( - com.android.internal.R.drawable.ic_phone, - ContentDescription.Resource( - R.string.ongoing_phone_call_content_description, - ), - ), - colors = ColorsModel.Themed, - startTimeMs = startTimeInElapsedRealtime, - getOnClickListener(state), - ) + // This block mimics OngoingCallController#updateChip. + if (state.startTimeMs <= 0L) { + // If the start time is invalid, don't show a timer and show just an + // icon. See b/192379214. + OngoingActivityChipModel.Shown.IconOnly( + icon = phoneIcon, + colors = ColorsModel.Themed, + getOnClickListener(state), + ) + } else { + val startTimeInElapsedRealtime = + state.startTimeMs - systemClock.currentTimeMillis() + + systemClock.elapsedRealtime() + OngoingActivityChipModel.Shown.Timer( + icon = phoneIcon, + colors = ColorsModel.Themed, + startTimeMs = startTimeInElapsedRealtime, + getOnClickListener(state), + ) + } } } } @@ -98,4 +99,14 @@ constructor( ) } } + + companion object { + private val phoneIcon = + Icon.Resource( + com.android.internal.R.drawable.ic_phone, + ContentDescription.Resource( + R.string.ongoing_phone_call_content_description, + ), + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt index 57f609b4b534..e8d895c3c266 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt @@ -36,6 +36,14 @@ sealed class OngoingActivityChipModel { */ open val onClickListener: View.OnClickListener?, ) : OngoingActivityChipModel() { + + /** This chip shows only an icon and nothing else. */ + data class IconOnly( + override val icon: Icon, + override val colors: ColorsModel, + override val onClickListener: View.OnClickListener?, + ) : Shown(icon, colors, onClickListener) + /** The chip shows a timer, counting up from [startTimeMs]. */ data class Timer( override val icon: Icon, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt index 50649a89e588..2c4848776b66 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt @@ -29,7 +29,8 @@ sealed interface OngoingCallModel { * @property startTimeMs the time that the phone call started, based on the notification's * `when` field. Importantly, this time is relative to * [com.android.systemui.util.time.SystemClock.currentTimeMillis], **not** - * [com.android.systemui.util.time.SystemClock.elapsedRealtime]. + * [com.android.systemui.util.time.SystemClock.elapsedRealtime]. This value can be 0 if the + * user has started an outgoing call that hasn't been answered yet - see b/192379214. * @property intent the intent associated with the call notification. */ data class InCall(val startTimeMs: Long, val intent: PendingIntent?) : OngoingCallModel diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt index 631befc5dd29..de36e407da84 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt @@ -161,6 +161,13 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa chipTextView.visibility = View.GONE } + is OngoingActivityChipModel.Shown.IconOnly -> { + chipTextView.visibility = View.GONE + // The Chronometer should be stopped to prevent leaks -- see b/192243808 and + // [Chronometer.start]. + chipTimeView.stop() + chipTimeView.visibility = View.GONE + } } updateChipTextPadding(chipModel, chipTextView, chipTimeView) } @@ -201,7 +208,8 @@ class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBa // Set as assertive so talkback will announce the countdown chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE } - is OngoingActivityChipModel.Shown.Timer -> { + is OngoingActivityChipModel.Shown.Timer, + is OngoingActivityChipModel.Shown.IconOnly -> { chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt index 6cab71fd8e88..1a6b420dace5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt @@ -69,7 +69,27 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - fun chip_inCall_isShownAsTimer() = + fun chip_inCall_zeroStartTime_isShownAsIconOnly() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null)) + + assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java) + } + + @Test + fun chip_inCall_negativeStartTime_isShownAsIconOnly() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = -2, intent = null)) + + assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java) + } + + @Test + fun chip_inCall_positiveStartTime_isShownAsTimer() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -97,7 +117,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - fun chip_iconIsPhone() = + fun chip_positiveStartTime_iconIsPhone() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -110,7 +130,20 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - fun chip_colorsAreThemed() = + fun chip_zeroStartTime_iconIsPhone() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null)) + + assertThat(((latest as OngoingActivityChipModel.Shown).icon as Icon.Resource).res) + .isEqualTo(com.android.internal.R.drawable.ic_phone) + assertThat((latest as OngoingActivityChipModel.Shown).icon!!.contentDescription) + .isNotNull() + } + + @Test + fun chip_positiveStartTime_colorsAreThemed() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -121,6 +154,17 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test + fun chip_zeroStartTime_colorsAreThemed() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = null)) + + assertThat((latest as OngoingActivityChipModel.Shown).colors) + .isEqualTo(ColorsModel.Themed) + } + + @Test fun chip_resetsCorrectly() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -159,7 +203,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - fun chip_inCall_validIntent_clickListenerLaunchesIntent() = + fun chip_inCall_positiveStartTime_validIntent_clickListenerLaunchesIntent() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -172,4 +216,19 @@ class CallChipViewModelTest : SysuiTestCase() { verify(kosmos.activityStarter).postStartActivityDismissingKeyguard(intent, null) } + + @Test + fun chip_inCall_zeroStartTime_validIntent_clickListenerLaunchesIntent() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + val intent = mock<PendingIntent>() + repo.setOngoingCallState(OngoingCallModel.InCall(startTimeMs = 0, intent = intent)) + val clickListener = (latest as OngoingActivityChipModel.Shown).onClickListener + assertThat(clickListener).isNotNull() + + clickListener!!.onClick(chipView) + + verify(kosmos.activityStarter).postStartActivityDismissingKeyguard(intent, null) + } } |