1 package com.android.systemui.qs.tiles 2 3 import android.app.AlarmManager 4 import android.app.AlarmManager.AlarmClockInfo 5 import android.content.Intent 6 import android.os.Handler 7 import android.os.Looper 8 import android.provider.AlarmClock 9 import android.service.quicksettings.Tile 10 import android.text.TextUtils 11 import android.text.format.DateFormat 12 import android.view.View 13 import androidx.annotation.VisibleForTesting 14 import com.android.internal.jank.InteractionJankMonitor 15 import com.android.internal.logging.MetricsLogger 16 import com.android.systemui.R 17 import com.android.systemui.animation.ActivityLaunchAnimator 18 import com.android.systemui.dagger.qualifiers.Background 19 import com.android.systemui.dagger.qualifiers.Main 20 import com.android.systemui.plugins.ActivityStarter 21 import com.android.systemui.plugins.FalsingManager 22 import com.android.systemui.plugins.qs.QSTile 23 import com.android.systemui.plugins.statusbar.StatusBarStateController 24 import com.android.systemui.qs.QSHost 25 import com.android.systemui.qs.QsEventLogger 26 import com.android.systemui.qs.logging.QSLogger 27 import com.android.systemui.qs.tileimpl.QSTileImpl 28 import com.android.systemui.settings.UserTracker 29 import com.android.systemui.statusbar.policy.NextAlarmController 30 import java.util.Locale 31 import javax.inject.Inject 32 33 class AlarmTile @Inject constructor( 34 host: QSHost, 35 uiEventLogger: QsEventLogger, 36 @Background backgroundLooper: Looper, 37 @Main mainHandler: Handler, 38 falsingManager: FalsingManager, 39 metricsLogger: MetricsLogger, 40 statusBarStateController: StatusBarStateController, 41 activityStarter: ActivityStarter, 42 qsLogger: QSLogger, 43 private val userTracker: UserTracker, 44 nextAlarmController: NextAlarmController 45 ) : QSTileImpl<QSTile.State>( 46 host, 47 uiEventLogger, 48 backgroundLooper, 49 mainHandler, 50 falsingManager, 51 metricsLogger, 52 statusBarStateController, 53 activityStarter, 54 qsLogger 55 ) { 56 57 private var lastAlarmInfo: AlarmManager.AlarmClockInfo? = null 58 private val icon = ResourceIcon.get(R.drawable.ic_alarm) 59 @VisibleForTesting 60 internal val defaultIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS) 61 private val callback = NextAlarmController.NextAlarmChangeCallback { nextAlarm -> 62 lastAlarmInfo = nextAlarm 63 refreshState() 64 } 65 66 init { 67 nextAlarmController.observe(this, callback) 68 } 69 70 override fun newTileState(): QSTile.State { 71 return QSTile.State().apply { 72 handlesLongClick = false 73 } 74 } 75 76 override fun handleClick(view: View?) { 77 val animationController = view?.let { 78 ActivityLaunchAnimator.Controller.fromView( 79 it, InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE) 80 } 81 val pendingIntent = lastAlarmInfo?.showIntent 82 if (pendingIntent != null) { 83 mActivityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController) 84 } else { 85 mActivityStarter.postStartActivityDismissingKeyguard(defaultIntent, 0, 86 animationController) 87 } 88 } 89 90 override fun handleUpdateState(state: QSTile.State, arg: Any?) { 91 state.icon = icon 92 state.label = tileLabel 93 lastAlarmInfo?.let { 94 state.secondaryLabel = formatNextAlarm(it) 95 state.state = Tile.STATE_ACTIVE 96 } ?: run { 97 state.secondaryLabel = mContext.getString(R.string.qs_alarm_tile_no_alarm) 98 state.state = Tile.STATE_INACTIVE 99 } 100 state.contentDescription = TextUtils.concat(state.label, ", ", state.secondaryLabel) 101 } 102 103 override fun getTileLabel(): CharSequence { 104 return mContext.getString(R.string.status_bar_alarm) 105 } 106 107 private fun formatNextAlarm(info: AlarmClockInfo): String { 108 val skeleton = if (use24HourFormat()) "EHm" else "Ehma" 109 val pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton) 110 return DateFormat.format(pattern, info.triggerTime).toString() 111 } 112 113 private fun use24HourFormat(): Boolean { 114 return DateFormat.is24HourFormat(mContext, userTracker.userId) 115 } 116 117 override fun getMetricsCategory(): Int { 118 return 0 119 } 120 121 override fun getLongClickIntent(): Intent? { 122 return null 123 } 124 125 companion object { 126 const val TILE_SPEC = "alarm" 127 } 128 } 129