Use SharedPreferences$Editor.apply() when possible, else use commit()

Change-Id: I48b18015214c90dd071b74bd807eb4346c0179c2
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index 1786957..b8fc7bc 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -198,7 +198,10 @@
      */
     private long getTimeBefore(String name, long max) {
         long time = mStorage.getLong(name, 0);
-        if (time > max) mStorage.edit().putLong(name, (time = max)).commit();
+        if (time > max) {
+            time = max;
+            SharedPreferencesCompat.apply(mStorage.edit().putLong(name, time));
+        }
         return time;
     }
 
@@ -211,7 +214,8 @@
      * trigger another operation; 0 to trigger immediately
      */
     public void setTriggerTimeMillis(long millis) {
-        mStorage.edit().putLong(PREFIX + "triggerTimeMillis", millis).commit();
+        SharedPreferencesCompat.apply(
+                mStorage.edit().putLong(PREFIX + "triggerTimeMillis", millis));
     }
 
     /**
@@ -222,10 +226,9 @@
      * when operations should be allowed again; 0 to remove moratorium
      */
     public void setMoratoriumTimeMillis(long millis) {
-        mStorage.edit()
-                .putLong(PREFIX + "moratoriumTimeMillis", millis)
-                .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis())
-                .commit();
+        SharedPreferencesCompat.apply(mStorage.edit()
+                   .putLong(PREFIX + "moratoriumTimeMillis", millis)
+                   .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis()));
     }
 
     /**
@@ -259,7 +262,8 @@
      * @param enabled if operations can be performed
      */
     public void setEnabledState(boolean enabled) {
-        mStorage.edit().putBoolean(PREFIX + "enabledState", enabled).commit();
+        SharedPreferencesCompat.apply(
+                mStorage.edit().putBoolean(PREFIX + "enabledState", enabled));
     }
 
     /**
@@ -269,12 +273,12 @@
     public void onSuccess() {
         resetTransientError();
         resetPermanentError();
-        mStorage.edit()
+        SharedPreferencesCompat.apply(mStorage.edit()
                 .remove(PREFIX + "errorCount")
                 .remove(PREFIX + "lastErrorTimeMillis")
                 .remove(PREFIX + "permanentError")
                 .remove(PREFIX + "triggerTimeMillis")
-                .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()).commit();
+                .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()));
     }
 
     /**
@@ -283,9 +287,11 @@
      * purposes.
      */
     public void onTransientError() {
-        mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis()).commit();
-        mStorage.edit().putInt(PREFIX + "errorCount",
-                mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit();
+        SharedPreferences.Editor editor = mStorage.edit();
+        editor.putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis());
+        editor.putInt(PREFIX + "errorCount",
+                mStorage.getInt(PREFIX + "errorCount", 0) + 1);
+        SharedPreferencesCompat.apply(editor);
     }
 
     /**
@@ -295,7 +301,7 @@
      * where there is reason to hope things might start working better.
      */
     public void resetTransientError() {
-        mStorage.edit().remove(PREFIX + "errorCount").commit();
+        SharedPreferencesCompat.apply(mStorage.edit().remove(PREFIX + "errorCount"));
     }
 
     /**
@@ -305,7 +311,7 @@
      * when the accounts database is updated).
      */
     public void onPermanentError() {
-        mStorage.edit().putBoolean(PREFIX + "permanentError", true).commit();
+        SharedPreferencesCompat.apply(mStorage.edit().putBoolean(PREFIX + "permanentError", true));
     }
 
     /**
@@ -313,7 +319,7 @@
      * allowing operations to be scheduled as normal.
      */
     public void resetPermanentError() {
-        mStorage.edit().remove(PREFIX + "permanentError").commit();
+        SharedPreferencesCompat.apply(mStorage.edit().remove(PREFIX + "permanentError"));
     }
 
     /**
diff --git a/common/java/com/android/common/SharedPreferencesCompat.java b/common/java/com/android/common/SharedPreferencesCompat.java
new file mode 100644
index 0000000..f779e97
--- /dev/null
+++ b/common/java/com/android/common/SharedPreferencesCompat.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import android.content.SharedPreferences;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Reflection utils to call SharedPreferences$Editor.apply when possible,
+ * falling back to commit when apply isn't available.
+ */
+public class SharedPreferencesCompat {
+    private static Method sApplyMethod;  // final
+    static {
+        try {
+            Class cls = SharedPreferences.Editor.class;
+            sApplyMethod = cls.getMethod("apply");
+        } catch (NoSuchMethodException unused) {
+            sApplyMethod = null;
+        }
+    }
+
+    public static void apply(SharedPreferences.Editor editor) {
+        if (sApplyMethod != null) {
+            try {
+                sApplyMethod.invoke(editor);
+                return;
+            } catch (InvocationTargetException unused) {
+                // fall through
+            } catch (IllegalAccessException unused) {
+                // fall through
+            }
+        }
+        editor.commit();
+    }
+}