Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/TimerViewModelTest.kt +5 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row.ui.viewmodel import android.app.Notification import android.app.PendingIntent import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 Loading Loading @@ -90,7 +91,8 @@ class TimerViewModelTest : SysuiTestCase() { name: String = "example", timeRemaining: Duration = Duration.ofMinutes(3), resumeIntent: PendingIntent? = null, resetIntent: PendingIntent? = null addMinuteAction: Notification.Action? = null, resetAction: Notification.Action? = null ) = TimerContentModel( icon = icon, Loading @@ -99,7 +101,8 @@ class TimerViewModelTest : SysuiTestCase() { Paused( timeRemaining = timeRemaining, resumeIntent = resumeIntent, resetIntent = resetIntent, addMinuteAction = addMinuteAction, resetAction = resetAction, ) ) } packages/SystemUI/res/layout/rich_ongoing_timer_notification.xml +13 −7 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ android:id="@+id/icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_close" app:tint="@android:color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/label" Loading Loading @@ -88,11 +87,10 @@ /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/mainButton" android:layout_width="124dp" android:layout_height="wrap_content" tools:text="Reset" tools:drawableStart="@android:drawable/ic_menu_add" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/altButton" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" Loading @@ -101,15 +99,23 @@ /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/altButton" tools:text="Reset" tools:drawableStart="@android:drawable/ic_menu_add" android:drawablePadding="2dp" android:drawableTint="@android:color/white" android:layout_width="124dp" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" app:layout_constraintStart_toEndOf="@id/mainButton" app:layout_constraintEnd_toEndOf="@id/resetButton" android:paddingEnd="4dp" /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/resetButton" android:layout_width="124dp" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" app:layout_constraintStart_toEndOf="@id/altButton" app:layout_constraintEnd_toEndOf="parent" android:paddingEnd="4dp" /> Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt +40 −8 Original line number Diff line number Diff line Loading @@ -122,12 +122,15 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : val timeRemaining = parseTimeDelta(remaining) TimerContentModel( icon = icon, name = total, // TODO: b/352142761 - define and use a string resource rather than " Timer". // (The UX isn't final so using " Timer" for now). name = total.replace("Σ", "") + " Timer", state = TimerContentModel.TimerState.Paused( timeRemaining = timeRemaining, resumeIntent = notification.findActionWithName("Resume"), resetIntent = notification.findActionWithName("Reset"), resumeIntent = notification.findStartIntent(), addMinuteAction = notification.findAddMinuteAction(), resetAction = notification.findResetAction(), ) ) } Loading @@ -136,12 +139,15 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : val finishTime = parseCurrentTime(current) + parseTimeDelta(remaining).toMillis() TimerContentModel( icon = icon, name = total, // TODO: b/352142761 - define and use a string resource rather than " Timer". // (The UX isn't final so using " Timer" for now). name = total.replace("Σ", "") + " Timer", state = TimerContentModel.TimerState.Running( finishTime = finishTime, pauseIntent = notification.findActionWithName("Pause"), addOneMinuteIntent = notification.findActionWithName("Add 1 min"), pauseIntent = notification.findPauseIntent(), addMinuteAction = notification.findAddMinuteAction(), resetAction = notification.findResetAction(), ) ) } Loading @@ -149,8 +155,34 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : } } private fun Notification.findActionWithName(name: String): PendingIntent? { return actions.firstOrNull { name == it.title?.toString() }?.actionIntent private fun Notification.findPauseIntent(): PendingIntent? { return actions .firstOrNull { it.actionIntent.intent?.action?.endsWith(".PAUSE_TIMER") == true } ?.actionIntent } private fun Notification.findStartIntent(): PendingIntent? { return actions .firstOrNull { it.actionIntent.intent?.action?.endsWith(".START_TIMER") == true } ?.actionIntent } // TODO: b/352142761 - switch to system attributes for label and icon. // - We probably want a consistent look for the Reset button. (Double check with UX.) // - Using the custom assets now since I couldn't an existing "Reset" icon. private fun Notification.findResetAction(): Notification.Action? { return actions.firstOrNull { it.actionIntent.intent?.action?.endsWith(".RESET_TIMER") == true } } // TODO: b/352142761 - check with UX on whether this should be required. // - Alternative is to allow for optional actions in addition to main and reset. // - For optional actions, we should take the custom label and icon. private fun Notification.findAddMinuteAction(): Notification.Action? { return actions.firstOrNull { it.actionIntent.intent?.action?.endsWith(".ADD_MINUTE_TIMER") == true } } private fun parseCurrentTime(current: String): Long { Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/RichOngoingClock.kt +8 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.row.shared import android.app.Notification import android.app.PendingIntent import java.time.Duration Loading @@ -32,6 +33,9 @@ data class TimerContentModel( ) : RichOngoingContentModel { /** The state (paused or running) of the timer, and relevant time */ sealed interface TimerState { val addMinuteAction: Notification.Action? val resetAction: Notification.Action? /** * Indicates a running timer * Loading @@ -41,7 +45,8 @@ data class TimerContentModel( data class Running( val finishTime: Long, val pauseIntent: PendingIntent?, val addOneMinuteIntent: PendingIntent?, override val addMinuteAction: Notification.Action?, override val resetAction: Notification.Action?, ) : TimerState /** Loading @@ -53,7 +58,8 @@ data class TimerContentModel( data class Paused( val timeRemaining: Duration, val resumeIntent: PendingIntent?, val resetIntent: PendingIntent?, override val addMinuteAction: Notification.Action?, override val resetAction: Notification.Action?, ) : TimerState } } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/view/TimerButtonView.kt +8 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,9 @@ package com.android.systemui.statusbar.notification.row.ui.view import android.annotation.DrawableRes import android.content.Context import android.graphics.BlendMode import android.util.AttributeSet import android.widget.Button import com.android.internal.widget.EmphasizedNotificationButton class TimerButtonView @JvmOverloads Loading @@ -28,14 +29,19 @@ constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0, ) : Button(context, attrs, defStyleAttr, defStyleRes) { ) : EmphasizedNotificationButton(context, attrs, defStyleAttr, defStyleRes) { private val Int.dp: Int get() = (this * context.resources.displayMetrics.density).toInt() fun setIcon(@DrawableRes icon: Int) { val drawable = context.getDrawable(icon) drawable?.mutate() drawable?.setTintList(textColors) drawable?.setTintBlendMode(BlendMode.SRC_IN) drawable?.setBounds(0, 0, 24.dp, 24.dp) setCompoundDrawablesRelative(drawable, null, null, null) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/TimerViewModelTest.kt +5 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row.ui.viewmodel import android.app.Notification import android.app.PendingIntent import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 Loading Loading @@ -90,7 +91,8 @@ class TimerViewModelTest : SysuiTestCase() { name: String = "example", timeRemaining: Duration = Duration.ofMinutes(3), resumeIntent: PendingIntent? = null, resetIntent: PendingIntent? = null addMinuteAction: Notification.Action? = null, resetAction: Notification.Action? = null ) = TimerContentModel( icon = icon, Loading @@ -99,7 +101,8 @@ class TimerViewModelTest : SysuiTestCase() { Paused( timeRemaining = timeRemaining, resumeIntent = resumeIntent, resetIntent = resetIntent, addMinuteAction = addMinuteAction, resetAction = resetAction, ) ) }
packages/SystemUI/res/layout/rich_ongoing_timer_notification.xml +13 −7 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ android:id="@+id/icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_close" app:tint="@android:color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/label" Loading Loading @@ -88,11 +87,10 @@ /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/mainButton" android:layout_width="124dp" android:layout_height="wrap_content" tools:text="Reset" tools:drawableStart="@android:drawable/ic_menu_add" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/altButton" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" Loading @@ -101,15 +99,23 @@ /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/altButton" tools:text="Reset" tools:drawableStart="@android:drawable/ic_menu_add" android:drawablePadding="2dp" android:drawableTint="@android:color/white" android:layout_width="124dp" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" app:layout_constraintStart_toEndOf="@id/mainButton" app:layout_constraintEnd_toEndOf="@id/resetButton" android:paddingEnd="4dp" /> <com.android.systemui.statusbar.notification.row.ui.view.TimerButtonView style="@*android:style/NotificationEmphasizedAction" android:id="@+id/resetButton" android:layout_width="124dp" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/bottomOfTop" app:layout_constraintStart_toEndOf="@id/altButton" app:layout_constraintEnd_toEndOf="parent" android:paddingEnd="4dp" /> Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationContentExtractor.kt +40 −8 Original line number Diff line number Diff line Loading @@ -122,12 +122,15 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : val timeRemaining = parseTimeDelta(remaining) TimerContentModel( icon = icon, name = total, // TODO: b/352142761 - define and use a string resource rather than " Timer". // (The UX isn't final so using " Timer" for now). name = total.replace("Σ", "") + " Timer", state = TimerContentModel.TimerState.Paused( timeRemaining = timeRemaining, resumeIntent = notification.findActionWithName("Resume"), resetIntent = notification.findActionWithName("Reset"), resumeIntent = notification.findStartIntent(), addMinuteAction = notification.findAddMinuteAction(), resetAction = notification.findResetAction(), ) ) } Loading @@ -136,12 +139,15 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : val finishTime = parseCurrentTime(current) + parseTimeDelta(remaining).toMillis() TimerContentModel( icon = icon, name = total, // TODO: b/352142761 - define and use a string resource rather than " Timer". // (The UX isn't final so using " Timer" for now). name = total.replace("Σ", "") + " Timer", state = TimerContentModel.TimerState.Running( finishTime = finishTime, pauseIntent = notification.findActionWithName("Pause"), addOneMinuteIntent = notification.findActionWithName("Add 1 min"), pauseIntent = notification.findPauseIntent(), addMinuteAction = notification.findAddMinuteAction(), resetAction = notification.findResetAction(), ) ) } Loading @@ -149,8 +155,34 @@ class RichOngoingNotificationContentExtractorImpl @Inject constructor() : } } private fun Notification.findActionWithName(name: String): PendingIntent? { return actions.firstOrNull { name == it.title?.toString() }?.actionIntent private fun Notification.findPauseIntent(): PendingIntent? { return actions .firstOrNull { it.actionIntent.intent?.action?.endsWith(".PAUSE_TIMER") == true } ?.actionIntent } private fun Notification.findStartIntent(): PendingIntent? { return actions .firstOrNull { it.actionIntent.intent?.action?.endsWith(".START_TIMER") == true } ?.actionIntent } // TODO: b/352142761 - switch to system attributes for label and icon. // - We probably want a consistent look for the Reset button. (Double check with UX.) // - Using the custom assets now since I couldn't an existing "Reset" icon. private fun Notification.findResetAction(): Notification.Action? { return actions.firstOrNull { it.actionIntent.intent?.action?.endsWith(".RESET_TIMER") == true } } // TODO: b/352142761 - check with UX on whether this should be required. // - Alternative is to allow for optional actions in addition to main and reset. // - For optional actions, we should take the custom label and icon. private fun Notification.findAddMinuteAction(): Notification.Action? { return actions.firstOrNull { it.actionIntent.intent?.action?.endsWith(".ADD_MINUTE_TIMER") == true } } private fun parseCurrentTime(current: String): Long { Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/shared/RichOngoingClock.kt +8 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.row.shared import android.app.Notification import android.app.PendingIntent import java.time.Duration Loading @@ -32,6 +33,9 @@ data class TimerContentModel( ) : RichOngoingContentModel { /** The state (paused or running) of the timer, and relevant time */ sealed interface TimerState { val addMinuteAction: Notification.Action? val resetAction: Notification.Action? /** * Indicates a running timer * Loading @@ -41,7 +45,8 @@ data class TimerContentModel( data class Running( val finishTime: Long, val pauseIntent: PendingIntent?, val addOneMinuteIntent: PendingIntent?, override val addMinuteAction: Notification.Action?, override val resetAction: Notification.Action?, ) : TimerState /** Loading @@ -53,7 +58,8 @@ data class TimerContentModel( data class Paused( val timeRemaining: Duration, val resumeIntent: PendingIntent?, val resetIntent: PendingIntent?, override val addMinuteAction: Notification.Action?, override val resetAction: Notification.Action?, ) : TimerState } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/view/TimerButtonView.kt +8 −2 Original line number Diff line number Diff line Loading @@ -18,8 +18,9 @@ package com.android.systemui.statusbar.notification.row.ui.view import android.annotation.DrawableRes import android.content.Context import android.graphics.BlendMode import android.util.AttributeSet import android.widget.Button import com.android.internal.widget.EmphasizedNotificationButton class TimerButtonView @JvmOverloads Loading @@ -28,14 +29,19 @@ constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0, ) : Button(context, attrs, defStyleAttr, defStyleRes) { ) : EmphasizedNotificationButton(context, attrs, defStyleAttr, defStyleRes) { private val Int.dp: Int get() = (this * context.resources.displayMetrics.density).toInt() fun setIcon(@DrawableRes icon: Int) { val drawable = context.getDrawable(icon) drawable?.mutate() drawable?.setTintList(textColors) drawable?.setTintBlendMode(BlendMode.SRC_IN) drawable?.setBounds(0, 0, 24.dp, 24.dp) setCompoundDrawablesRelative(drawable, null, null, null) } }