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