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 18 19 import android.annotation.SuppressLint 20 import android.content.BroadcastReceiver 21 import android.content.Context 22 import android.content.Intent 23 24 import com.android.deskclock.AlarmAlertWakeLock.createPartialWakeLock 25 import com.android.deskclock.alarms.AlarmStateManager 26 import com.android.deskclock.controller.Controller 27 import com.android.deskclock.data.DataModel 28 29 class AlarmInitReceiver : BroadcastReceiver() { 30 /** 31 * This receiver handles a variety of actions: 32 * 33 * <ul> 34 * <li>Clean up backup data that was recently restored to this device on 35 * ACTION_COMPLETE_RESTORE.</li> 36 * <li>Reset timers and stopwatch on ACTION_BOOT_COMPLETED</li> 37 * <li>Fix alarm states on ACTION_BOOT_COMPLETED, TIME_SET, TIMEZONE_CHANGED, 38 * and LOCALE_CHANGED</li> 39 * <li>Rebuild notifications on MY_PACKAGE_REPLACED</li> 40 * </ul> 41 */ onReceivenull42 override fun onReceive(context: Context, intent: Intent) { 43 val action = intent.action 44 LogUtils.i("AlarmInitReceiver $action") 45 46 val result = goAsync() 47 val wl = createPartialWakeLock(context) 48 wl.acquire() 49 50 // We need to increment the global id out of the async task to prevent race conditions 51 DataModel.dataModel.updateGlobalIntentId() 52 53 // Updates stopwatch and timer data after a device reboot so they are as accurate as 54 // possible. 55 if (ACTION_BOOT_COMPLETED == action) { 56 DataModel.dataModel.updateAfterReboot() 57 // Stopwatch and timer data need to be updated on time change so the reboot 58 // functionality works as expected. 59 } else if (Intent.ACTION_TIME_CHANGED == action) { 60 DataModel.dataModel.updateAfterTimeSet() 61 } 62 63 // Update shortcuts so they exist for the user. 64 if (Intent.ACTION_BOOT_COMPLETED == action || Intent.ACTION_LOCALE_CHANGED == action) { 65 Controller.getController().updateShortcuts() 66 NotificationUtils.updateNotificationChannels(context) 67 } 68 69 // Notifications are canceled by the system on application upgrade. This broadcast signals 70 // that the new app is free to rebuild the notifications using the existing data. 71 // Additionally on new app installs, make sure to enable shortcuts immediately as opposed 72 // to waiting for system reboot. 73 if (Intent.ACTION_MY_PACKAGE_REPLACED == action) { 74 DataModel.dataModel.updateAllNotifications() 75 Controller.getController().updateShortcuts() 76 } 77 78 AsyncHandler.post { 79 try { 80 // Process restored data if any exists 81 if (!DeskClockBackupAgent.processRestoredData(context)) { 82 // Update all the alarm instances on time change event 83 AlarmStateManager.fixAlarmInstances(context) 84 } 85 } finally { 86 result.finish() 87 wl.release() 88 LogUtils.v("AlarmInitReceiver finished") 89 } 90 } 91 } 92 93 companion object { 94 /** 95 * When running on N devices, we're interested in the boot completed event that is sent 96 * while the user is still locked, so that we can schedule alarms. 97 */ 98 @SuppressLint("InlinedApi") 99 private val ACTION_BOOT_COMPLETED = if (Utils.isNOrLater()) { 100 Intent.ACTION_LOCKED_BOOT_COMPLETED 101 } else { 102 Intent.ACTION_BOOT_COMPLETED 103 } 104 } 105 }