Loading packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +30 −19 Original line number Diff line number Diff line Loading @@ -55,21 +55,21 @@ 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). // 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 = Icon.Resource( com.android.internal.R.drawable.ic_phone, ContentDescription.Resource( R.string.ongoing_phone_call_content_description, ), ), icon = phoneIcon, colors = ColorsModel.Themed, startTimeMs = startTimeInElapsedRealtime, getOnClickListener(state), Loading @@ -77,6 +77,7 @@ constructor( } } } } .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden) private fun getOnClickListener(state: OngoingCallModel.InCall): View.OnClickListener? { Loading @@ -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, ), ) } } packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt +9 −1 Original line number Diff line number Diff line Loading @@ -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) } Loading Loading @@ -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 } } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +63 −4 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -97,7 +117,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test fun chip_iconIsPhone() = fun chip_positiveStartTime_iconIsPhone() = testScope.runTest { val latest by collectLastValue(underTest.chip) Loading @@ -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) Loading @@ -120,6 +153,17 @@ class CallChipViewModelTest : SysuiTestCase() { .isEqualTo(ColorsModel.Themed) } @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 { Loading Loading @@ -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) Loading @@ -170,6 +214,21 @@ class CallChipViewModelTest : SysuiTestCase() { clickListener!!.onClick(chipView) 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) } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +30 −19 Original line number Diff line number Diff line Loading @@ -55,21 +55,21 @@ 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). // 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 = Icon.Resource( com.android.internal.R.drawable.ic_phone, ContentDescription.Resource( R.string.ongoing_phone_call_content_description, ), ), icon = phoneIcon, colors = ColorsModel.Themed, startTimeMs = startTimeInElapsedRealtime, getOnClickListener(state), Loading @@ -77,6 +77,7 @@ constructor( } } } } .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden) private fun getOnClickListener(state: OngoingCallModel.InCall): View.OnClickListener? { Loading @@ -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, ), ) } }
packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt +9 −1 Original line number Diff line number Diff line Loading @@ -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) } Loading Loading @@ -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 } } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +63 −4 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -97,7 +117,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test fun chip_iconIsPhone() = fun chip_positiveStartTime_iconIsPhone() = testScope.runTest { val latest by collectLastValue(underTest.chip) Loading @@ -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) Loading @@ -120,6 +153,17 @@ class CallChipViewModelTest : SysuiTestCase() { .isEqualTo(ColorsModel.Themed) } @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 { Loading Loading @@ -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) Loading @@ -170,6 +214,21 @@ class CallChipViewModelTest : SysuiTestCase() { clickListener!!.onClick(chipView) 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) } }