summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Lemieux <jplemieux@google.com>2015-07-30 20:28:18 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2015-07-30 20:28:18 +0000
commitebf56a31b1d8fdda055397e6c5efa9a4c0aed9f2 (patch)
tree72a162bfd8e02dbfb2e83cd7c2c2275c6c12d5fa /src
parent17a237e4df0249417f44e7b34fc15ec7f28483ed (diff)
parent32e2e0440cc4219dfe200bcf025508b740ec7cb1 (diff)
downloadandroid_packages_apps_DeskClock-ebf56a31b1d8fdda055397e6c5efa9a4c0aed9f2.tar.gz
android_packages_apps_DeskClock-ebf56a31b1d8fdda055397e6c5efa9a4c0aed9f2.tar.bz2
android_packages_apps_DeskClock-ebf56a31b1d8fdda055397e6c5efa9a4c0aed9f2.zip
am 32e2e044: Execute cleanup code in a new app instance after a restore
* commit '32e2e0440cc4219dfe200bcf025508b740ec7cb1': Execute cleanup code in a new app instance after a restore
Diffstat (limited to 'src')
-rw-r--r--src/com/android/deskclock/AlarmInitReceiver.java57
-rw-r--r--src/com/android/deskclock/DeskClockBackupAgent.java85
2 files changed, 115 insertions, 27 deletions
diff --git a/src/com/android/deskclock/AlarmInitReceiver.java b/src/com/android/deskclock/AlarmInitReceiver.java
index ec5813a40..e248e2fd1 100644
--- a/src/com/android/deskclock/AlarmInitReceiver.java
+++ b/src/com/android/deskclock/AlarmInitReceiver.java
@@ -33,8 +33,16 @@ public class AlarmInitReceiver extends BroadcastReceiver {
private static final String PREF_VOLUME_DEF_DONE = "vol_def_done";
/**
- * Sets alarm on ACTION_BOOT_COMPLETED. Resets alarm on
- * TIME_SET, TIMEZONE_CHANGED
+ * This receiver handles a variety of actions:
+ *
+ * <ul>
+ * <li>Clean up backup data that was recently restored to this device on
+ * ACTION_COMPLETE_RESTORE.</li>
+ * <li>Clean up backup data that was recently restored to this device and reset timers and
+ * clear stopwatch on ACTION_BOOT_COMPLETED</li>
+ * <li>Fix alarm states on ACTION_BOOT_COMPLETED, TIME_SET, TIMEZONE_CHANGED,
+ * and LOCALE_CHANGED</li>
+ * </ul>
*/
@Override
public void onReceive(final Context context, Intent intent) {
@@ -45,32 +53,37 @@ public class AlarmInitReceiver extends BroadcastReceiver {
final WakeLock wl = AlarmAlertWakeLock.createPartialWakeLock(context);
wl.acquire();
- // We need to increment the global id out of the async task to prevent
- // race conditions
+ // We need to increment the global id out of the async task to prevent race conditions
AlarmStateManager.updateGlobalIntentId(context);
+
AsyncHandler.post(new Runnable() {
@Override public void run() {
- if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- // Clear stopwatch and timers data
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(context);
- LogUtils.v("AlarmInitReceiver - Reset timers and clear stopwatch data");
- TimerObj.resetTimersInSharedPrefs(prefs);
- Utils.clearSwSharedPref(prefs);
+ try {
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ // Clear stopwatch and timers data
+ final SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ LogUtils.v("AlarmInitReceiver - Reset timers and clear stopwatch data");
+ TimerObj.resetTimersInSharedPrefs(prefs);
+ Utils.clearSwSharedPref(prefs);
- if (!prefs.getBoolean(PREF_VOLUME_DEF_DONE, false)) {
- // Fix the default
- LogUtils.v("AlarmInitReceiver - resetting volume button default");
- switchVolumeButtonDefault(prefs);
+ if (!prefs.getBoolean(PREF_VOLUME_DEF_DONE, false)) {
+ // Fix the default
+ LogUtils.v("AlarmInitReceiver - resetting volume button default");
+ switchVolumeButtonDefault(prefs);
+ }
}
- }
-
- // Update all the alarm instances on time change event
- AlarmStateManager.fixAlarmInstances(context);
- result.finish();
- LogUtils.v("AlarmInitReceiver finished");
- wl.release();
+ // Process restored data if any exists
+ if (!DeskClockBackupAgent.processRestoredData(context)) {
+ // Update all the alarm instances on time change event
+ AlarmStateManager.fixAlarmInstances(context);
+ }
+ } finally {
+ result.finish();
+ wl.release();
+ LogUtils.v("AlarmInitReceiver finished");
+ }
}
});
}
diff --git a/src/com/android/deskclock/DeskClockBackupAgent.java b/src/com/android/deskclock/DeskClockBackupAgent.java
index 3eb63fe36..841382476 100644
--- a/src/com/android/deskclock/DeskClockBackupAgent.java
+++ b/src/com/android/deskclock/DeskClockBackupAgent.java
@@ -16,10 +16,19 @@
package com.android.deskclock;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import com.android.deskclock.alarms.AlarmStateManager;
@@ -33,6 +42,11 @@ import java.util.List;
public class DeskClockBackupAgent extends BackupAgent {
+ private static final String KEY_RESTORE_FINISHED = "restore_finished";
+
+ public static final String ACTION_COMPLETE_RESTORE =
+ "com.android.deskclock.action.COMPLETE_RESTORE";
+
private static final String TAG = "DeskClockBackupAgent";
@Override
@@ -56,28 +70,89 @@ public class DeskClockBackupAgent extends BackupAgent {
super.onRestoreFile(data, size, destination, type, mode, mtime);
}
+ /**
+ * When this method is called during backup/restore, the application is executing in a
+ * "minimalist" state. Because of this, the application's ContentResolver cannot be used.
+ * Consequently, the work of scheduling alarms on the restore device cannot be done here.
+ * Instead, a future callback to DeskClock is used as a signal to reschedule the alarms. The
+ * future callback may take the form of ACTION_BOOT_COMPLETED if the device is not yet fully
+ * booted (i.e. the restore occurred as part of the setup wizard). If the device is booted, an
+ * ACTION_COMPLETE_RESTORE broadcast is scheduled 10 seconds in the future to give
+ * backup/restore enough time to kill the Clock process. Both of these future callbacks result
+ * in the execution of {@link #processRestoredData(Context)}.
+ */
@Override
public void onRestoreFinished() {
- // Now that alarms have been restored, schedule them in AlarmManager.
- final List<Alarm> alarms = Alarm.getAlarms(getContentResolver(), null);
+ // Write a preference to indicate a data restore has been completed.
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ prefs.edit().putBoolean(KEY_RESTORE_FINISHED, true).apply();
+
+ // If device boot is not yet completed, use ACTION_BOOT_COMPLETED to trigger completion of
+ // the data restore process at a safer time.
+ if (registerReceiver(null, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)) != null) {
+ LogUtils.i(TAG, "Waiting for %s to complete the data restore",
+ Intent.ACTION_BOOT_COMPLETED);
+ return;
+ }
+
+ // Otherwise, the device is already booted, so schedule a custom broadcast to start the
+ // application in 10 seconds.
+
+ // Create an Intent to send into DeskClock indicating restore is complete.
+ final PendingIntent restoreIntent = PendingIntent.getBroadcast(this, 0,
+ new Intent(ACTION_COMPLETE_RESTORE).setClass(this, AlarmInitReceiver.class),
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT);
+
+ // Deliver the Intent 10 seconds from now.
+ final long triggerAtMillis = SystemClock.elapsedRealtime() + 10000;
+
+ // Schedule the Intent delivery in AlarmManager.
+ final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, restoreIntent);
+
+ LogUtils.i(TAG, "Waiting for %s to complete the data restore", ACTION_COMPLETE_RESTORE);
+ }
+
+ /**
+ * @param context a context to access resources and services
+ * @return {@code true} if restore data was processed; {@code false} otherwise.
+ */
+ public static boolean processRestoredData(Context context) {
+ // If the preference indicates data was not recently restored, there is nothing to do.
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ if (!prefs.getBoolean(KEY_RESTORE_FINISHED, false)) {
+ return false;
+ }
+
+ LogUtils.i(TAG, "processRestoredData() started");
+
+ // Now that alarms have been restored, schedule new instances in AlarmManager.
+ final ContentResolver contentResolver = context.getContentResolver();
+ final List<Alarm> alarms = Alarm.getAlarms(contentResolver, null);
final Calendar now = Calendar.getInstance();
for (Alarm alarm : alarms) {
// Remove any instances that may currently exist for the alarm;
// these aren't relevant on the restore device and we'll recreate them below.
- AlarmStateManager.deleteAllInstances(this, alarm.id);
+ AlarmStateManager.deleteAllInstances(context, alarm.id);
if (alarm.enabled) {
// Create the next alarm instance to schedule.
AlarmInstance alarmInstance = alarm.createInstanceAfter(now);
// Add the next alarm instance to the database.
- alarmInstance = AlarmInstance.addInstance(getContentResolver(), alarmInstance);
+ alarmInstance = AlarmInstance.addInstance(contentResolver, alarmInstance);
// Schedule the next alarm instance in AlarmManager.
- AlarmStateManager.registerInstance(this, alarmInstance, true);
+ AlarmStateManager.registerInstance(context, alarmInstance, true);
LogUtils.i(TAG, "DeskClockBackupAgent scheduled alarm instance: %s", alarmInstance);
}
}
+
+ // Remove the preference to avoid executing this logic multiple times.
+ prefs.edit().remove(KEY_RESTORE_FINISHED).apply();
+
+ LogUtils.i(TAG, "processRestoredData() completed");
+ return true;
}
} \ No newline at end of file