1 /* 2 * Copyright (C) 2020 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.deskclock.alarms 18 19 import android.content.Context 20 import android.content.Intent 21 import android.os.Bundle 22 import android.os.Vibrator 23 import androidx.fragment.app.Fragment 24 25 import com.android.deskclock.AlarmClockFragment 26 import com.android.deskclock.LabelDialogFragment 27 import com.android.deskclock.LogUtils 28 import com.android.deskclock.R 29 import com.android.deskclock.alarms.dataadapter.AlarmItemHolder 30 import com.android.deskclock.data.DataModel 31 import com.android.deskclock.data.Weekdays 32 import com.android.deskclock.events.Events 33 import com.android.deskclock.provider.Alarm 34 import com.android.deskclock.provider.AlarmInstance 35 import com.android.deskclock.provider.ClockContract.InstancesColumns 36 import com.android.deskclock.ringtone.RingtonePickerActivity 37 38 import java.util.Calendar 39 40 /** 41 * Click handler for an alarm time item. 42 */ 43 class AlarmTimeClickHandler( 44 private val mFragment: Fragment, 45 savedState: Bundle?, 46 private val mAlarmUpdateHandler: AlarmUpdateHandler, 47 private val mScrollHandler: ScrollHandler 48 ) { 49 50 private val mContext: Context = mFragment.requireActivity().getApplicationContext() 51 private var mSelectedAlarm: Alarm? = null 52 private var mPreviousDaysOfWeekMap: Bundle? = null 53 54 init { 55 if (savedState != null) { 56 mPreviousDaysOfWeekMap = savedState.getBundle(KEY_PREVIOUS_DAY_MAP) 57 } 58 if (mPreviousDaysOfWeekMap == null) { 59 mPreviousDaysOfWeekMap = Bundle() 60 } 61 } 62 setSelectedAlarmnull63 fun setSelectedAlarm(selectedAlarm: Alarm?) { 64 mSelectedAlarm = selectedAlarm 65 } 66 saveInstancenull67 fun saveInstance(outState: Bundle) { 68 outState.putBundle(KEY_PREVIOUS_DAY_MAP, mPreviousDaysOfWeekMap) 69 } 70 setAlarmEnablednull71 fun setAlarmEnabled(alarm: Alarm, newState: Boolean) { 72 if (newState != alarm.enabled) { 73 alarm.enabled = newState 74 Events.sendAlarmEvent(if (newState) R.string.action_enable else R.string.action_disable, 75 R.string.label_deskclock) 76 mAlarmUpdateHandler.asyncUpdateAlarm(alarm, alarm.enabled, minorUpdate = false) 77 LOGGER.d("Updating alarm enabled state to $newState") 78 } 79 } 80 setAlarmVibrationEnablednull81 fun setAlarmVibrationEnabled(alarm: Alarm, newState: Boolean) { 82 if (newState != alarm.vibrate) { 83 alarm.vibrate = newState 84 Events.sendAlarmEvent(R.string.action_toggle_vibrate, R.string.label_deskclock) 85 mAlarmUpdateHandler.asyncUpdateAlarm(alarm, popToast = false, minorUpdate = true) 86 LOGGER.d("Updating vibrate state to $newState") 87 88 if (newState) { 89 // Buzz the vibrator to preview the alarm firing behavior. 90 val v: Vibrator = mContext.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator 91 if (v.hasVibrator()) { 92 v.vibrate(300) 93 } 94 } 95 } 96 } 97 setAlarmRepeatEnablednull98 fun setAlarmRepeatEnabled(alarm: Alarm, isEnabled: Boolean) { 99 val now = Calendar.getInstance() 100 val oldNextAlarmTime = alarm.getNextAlarmTime(now) 101 val alarmId = alarm.id.toString() 102 if (isEnabled) { 103 // Set all previously set days 104 // or 105 // Set all days if no previous. 106 val bitSet: Int = mPreviousDaysOfWeekMap!!.getInt(alarmId) 107 alarm.daysOfWeek = Weekdays.fromBits(bitSet) 108 if (!alarm.daysOfWeek.isRepeating) { 109 alarm.daysOfWeek = Weekdays.ALL 110 } 111 } else { 112 // Remember the set days in case the user wants it back. 113 val bitSet = alarm.daysOfWeek.bits 114 mPreviousDaysOfWeekMap!!.putInt(alarmId, bitSet) 115 116 // Remove all repeat days 117 alarm.daysOfWeek = Weekdays.NONE 118 } 119 120 // if the change altered the next scheduled alarm time, tell the user 121 val newNextAlarmTime = alarm.getNextAlarmTime(now) 122 val popupToast = oldNextAlarmTime != newNextAlarmTime 123 Events.sendAlarmEvent(R.string.action_toggle_repeat_days, R.string.label_deskclock) 124 mAlarmUpdateHandler.asyncUpdateAlarm(alarm, popupToast, minorUpdate = false) 125 } 126 setDayOfWeekEnablednull127 fun setDayOfWeekEnabled(alarm: Alarm, checked: Boolean, index: Int) { 128 val now = Calendar.getInstance() 129 val oldNextAlarmTime = alarm.getNextAlarmTime(now) 130 131 val weekday = DataModel.dataModel.weekdayOrder.calendarDays[index] 132 alarm.daysOfWeek = alarm.daysOfWeek.setBit(weekday, checked) 133 134 // if the change altered the next scheduled alarm time, tell the user 135 val newNextAlarmTime = alarm.getNextAlarmTime(now) 136 val popupToast = oldNextAlarmTime != newNextAlarmTime 137 mAlarmUpdateHandler.asyncUpdateAlarm(alarm, popupToast, minorUpdate = false) 138 } 139 onDeleteClickednull140 fun onDeleteClicked(itemHolder: AlarmItemHolder) { 141 if (mFragment is AlarmClockFragment) { 142 (mFragment as AlarmClockFragment).removeItem(itemHolder) 143 } 144 val alarm = itemHolder.item 145 Events.sendAlarmEvent(R.string.action_delete, R.string.label_deskclock) 146 mAlarmUpdateHandler.asyncDeleteAlarm(alarm) 147 LOGGER.d("Deleting alarm.") 148 } 149 onClockClickednull150 fun onClockClicked(alarm: Alarm) { 151 mSelectedAlarm = alarm 152 Events.sendAlarmEvent(R.string.action_set_time, R.string.label_deskclock) 153 TimePickerDialogFragment.show(mFragment, alarm.hour, alarm.minutes) 154 } 155 dismissAlarmInstancenull156 fun dismissAlarmInstance(alarmInstance: AlarmInstance) { 157 val dismissIntent: Intent = AlarmStateManager.createStateChangeIntent( 158 mContext, AlarmStateManager.ALARM_DISMISS_TAG, alarmInstance, 159 InstancesColumns.PREDISMISSED_STATE) 160 mContext.startService(dismissIntent) 161 mAlarmUpdateHandler.showPredismissToast(alarmInstance) 162 } 163 onRingtoneClickednull164 fun onRingtoneClicked(context: Context, alarm: Alarm) { 165 mSelectedAlarm = alarm 166 Events.sendAlarmEvent(R.string.action_set_ringtone, R.string.label_deskclock) 167 168 val intent: Intent = RingtonePickerActivity.createAlarmRingtonePickerIntent(context, alarm) 169 context.startActivity(intent) 170 } 171 onEditLabelClickednull172 fun onEditLabelClicked(alarm: Alarm) { 173 Events.sendAlarmEvent(R.string.action_set_label, R.string.label_deskclock) 174 val fragment = LabelDialogFragment.newInstance(alarm, alarm.label, mFragment.getTag()) 175 LabelDialogFragment.show(mFragment.getFragmentManager(), fragment) 176 } 177 onTimeSetnull178 fun onTimeSet(hourOfDay: Int, minute: Int) { 179 if (mSelectedAlarm == null) { 180 // If mSelectedAlarm is null then we're creating a new alarm. 181 val a = Alarm() 182 a.hour = hourOfDay 183 a.minutes = minute 184 a.enabled = true 185 mAlarmUpdateHandler.asyncAddAlarm(a) 186 } else { 187 mSelectedAlarm!!.hour = hourOfDay 188 mSelectedAlarm!!.minutes = minute 189 mSelectedAlarm!!.enabled = true 190 mScrollHandler.setSmoothScrollStableId(mSelectedAlarm!!.id) 191 mAlarmUpdateHandler 192 .asyncUpdateAlarm(mSelectedAlarm!!, popToast = true, minorUpdate = false) 193 mSelectedAlarm = null 194 } 195 } 196 197 companion object { 198 private val LOGGER = LogUtils.Logger("AlarmTimeClickHandler") 199 200 private const val KEY_PREVIOUS_DAY_MAP = "previousDayMap" 201 } 202 }