1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.qs.tiles.impl.alarm.ui.mapper 18 19 import android.content.res.Resources 20 import android.content.res.Resources.Theme 21 import com.android.systemui.common.shared.model.Icon 22 import com.android.systemui.qs.tiles.base.shared.model.QSTileConfig 23 import com.android.systemui.qs.tiles.base.shared.model.QSTileState 24 import com.android.systemui.qs.tiles.base.ui.model.QSTileDataToStateMapper 25 import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel 26 import com.android.systemui.res.R 27 import com.android.systemui.shade.ShadeDisplayAware 28 import com.android.systemui.util.time.SystemClock 29 import java.time.Instant 30 import java.time.LocalDateTime 31 import java.time.format.DateTimeFormatter 32 import java.util.TimeZone 33 import javax.inject.Inject 34 35 /** Maps [AlarmTileModel] to [QSTileState]. */ 36 class AlarmTileMapper 37 @Inject 38 constructor( 39 @ShadeDisplayAware private val resources: Resources, 40 private val theme: Theme, 41 private val clock: SystemClock, 42 ) : QSTileDataToStateMapper<AlarmTileModel> { 43 companion object { 44 val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E hh:mm a") 45 val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E HH:mm") 46 val formatterDateOnly: DateTimeFormatter = DateTimeFormatter.ofPattern("E MMM d") 47 } 48 mapnull49 override fun map(config: QSTileConfig, data: AlarmTileModel): QSTileState = 50 QSTileState.build(resources, theme, config.uiConfig) { 51 when (data) { 52 is AlarmTileModel.NextAlarmSet -> { 53 activationState = QSTileState.ActivationState.ACTIVE 54 55 val alarmDateTime = 56 LocalDateTime.ofInstant( 57 Instant.ofEpochMilli(data.alarmClockInfo.triggerTime), 58 TimeZone.getDefault().toZoneId(), 59 ) 60 61 val nowDateTime = 62 LocalDateTime.ofInstant( 63 Instant.ofEpochMilli(clock.currentTimeMillis()), 64 TimeZone.getDefault().toZoneId(), 65 ) 66 67 // Edge case: If it's 8:00:30 right now and alarm is requested for next week at 68 // 8:00:29, we still want to show the date. Same at nanosecond level. 69 val nextWeekThisTime = nowDateTime.plusWeeks(1).withSecond(0).withNano(0) 70 71 // is the alarm over a week away? 72 val shouldShowDateAndHideTime = alarmDateTime >= nextWeekThisTime 73 74 if (shouldShowDateAndHideTime) { 75 secondaryLabel = formatterDateOnly.format(alarmDateTime) 76 } else { 77 secondaryLabel = 78 if (data.is24HourFormat) formatter24Hour.format(alarmDateTime) 79 else formatter12Hour.format(alarmDateTime) 80 } 81 } 82 is AlarmTileModel.NoAlarmSet -> { 83 activationState = QSTileState.ActivationState.INACTIVE 84 secondaryLabel = resources.getString(R.string.qs_alarm_tile_no_alarm) 85 } 86 } 87 val iconRes = R.drawable.ic_alarm 88 icon = Icon.Loaded(resources.getDrawable(iconRes, theme), null, iconRes) 89 sideViewIcon = QSTileState.SideViewIcon.Chevron 90 contentDescription = label 91 supportedActions = setOf(QSTileState.UserAction.CLICK) 92 } 93 } 94