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