Make enable/provisioning of the backup service a two-step process

This CL adds the concept of 'provisioned' to the backup manager.  No backups
will be scheduled until the user has indicated that backups are to be enabled
*and* has clicked all the way through the setup wizard.

When the user first turns on the backup system, the delay before the initial
backup pass is different from the periodic backup interval.  Currently that
initial delay is 12 hours.  The intent here is to guess at a less-active time
for performing that first backup pass.

NOTE: currently the backup service defaults to 'provisioned'.  Once the real
code goes live in Setup Wizard, this will be changed to default to
not-provisioned until the user has confirmed all the relevant UI.
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index d4933ac..9d181be 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -73,6 +73,13 @@
     void setBackupEnabled(boolean isEnabled);
 
     /**
+     * Indicate that any necessary one-time provisioning has occurred.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     */
+    void setBackupProvisioned(boolean isProvisioned);
+
+    /**
      * Report whether the backup mechanism is currently enabled.
      *
      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7017333..7f63bff 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2269,13 +2269,20 @@
         public static final String USE_LOCATION_FOR_SERVICES = "use_location";
 
         /**
-         * Controls whether data backup is enabled.
+         * Controls whether settings backup is enabled.
          * Type: int ( 0 = disabled, 1 = enabled )
          * @hide
          */
         public static final String BACKUP_ENABLED = "backup_enabled";
 
         /**
+         * Indicates whether settings backup has been fully provisioned.
+         * Type: int ( 0 = unprovisioned, 1 = fully provisioned )
+         * @hide
+         */
+        public static final String BACKUP_PROVISIONED = "backup_provisioned";
+
+        /**
          * Component of the transport to use for backup/restore.
          * @hide
          */
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4b5c3df..2ae9fc5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -81,6 +81,10 @@
     // trigger an immediate pass.
     private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
 
+    // The amount of time between the initial provisioning of the device and
+    // the first backup pass.
+    private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
+
     private static final String RUN_BACKUP_ACTION = "_backup_run_";
     private static final int MSG_RUN_BACKUP = 1;
     private static final int MSG_RUN_FULL_BACKUP = 2;
@@ -97,6 +101,7 @@
     private AlarmManager mAlarmManager;
 
     private boolean mEnabled;   // access to this is synchronized on 'this'
+    private boolean mProvisioned;
     private PowerManager.WakeLock mWakelock;
     private final BackupHandler mBackupHandler = new BackupHandler();
     private PendingIntent mRunBackupIntent;
@@ -188,6 +193,9 @@
         // Set up our bookkeeping
         boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.BACKUP_ENABLED, 0) != 0;
+        // !!! TODO: mProvisioned needs to default to 0, not 1.
+        mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.BACKUP_PROVISIONED, 1) != 0;
         mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
         mDataDir = Environment.getDownloadCacheDirectory();
 
@@ -1301,7 +1309,7 @@
         }
     }
 
-    // Enable/disable the backup transport
+    // Enable/disable the backup service
     public void setBackupEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "setBackupEnabled");
@@ -1314,11 +1322,9 @@
         }
 
         synchronized (mQueueLock) {
-            if (enable && !wasEnabled) {
+            if (enable && !wasEnabled && mProvisioned) {
                 // if we've just been enabled, start scheduling backup passes
-                long when = System.currentTimeMillis() + BACKUP_INTERVAL;
-                mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
-                        BACKUP_INTERVAL, mRunBackupIntent);
+                startBackupAlarmsLocked(BACKUP_INTERVAL);
             } else if (!enable) {
                 // No longer enabled, so stop running backups
                 mAlarmManager.cancel(mRunBackupIntent);
@@ -1326,6 +1332,36 @@
         }
     }
 
+    // Mark the backup service as having been provisioned
+    public void setBackupProvisioned(boolean available) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+                "setBackupProvisioned");
+
+        boolean wasProvisioned = mProvisioned;
+        synchronized (this) {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.BACKUP_PROVISIONED, available ? 1 : 0);
+            mProvisioned = available;
+        }
+
+        synchronized (mQueueLock) {
+            if (available && !wasProvisioned && mEnabled) {
+                // we're now good to go, so start the backup alarms
+                startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+            } else if (!available) {
+                // No longer enabled, so stop running backups
+                Log.w(TAG, "Backup service no longer provisioned");
+                mAlarmManager.cancel(mRunBackupIntent);
+            }
+        }
+    }
+
+    private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
+        long when = System.currentTimeMillis() + delayBeforeFirstBackup;
+        mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
+                BACKUP_INTERVAL, mRunBackupIntent);
+    }
+
     // Report whether the backup mechanism is currently enabled
     public boolean isBackupEnabled() {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
@@ -1506,7 +1542,8 @@
         synchronized (mQueueLock) {
             long oldId = Binder.clearCallingIdentity();
 
-            pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
+            pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+                    + " / " + (!mProvisioned ? "not " : "") + "provisioned");
             pw.println("Available transports:");
             for (String t : listAllTransports()) {
                 String pad = (t.equals(mCurrentTransport)) ? "  * " : "    ";