Fallback to SharedPreferences$Editor.commit() when no apply() exists.

Gingerbread widened the SharedPreferences.Editor interface, adding an
apply() method.  Most people don't implement this interface
themselves, but a couple apps do.

A few spots in the core framework take a SharedPreferences[.Editor]
from apps, which might be a pre-Gingerbread implementation without an
apply() method.  This patch makes sure we never depend on the presence
of an apply() method, falling back to commit() if apply() isn't
available.

Change-Id: I32693ac9227a60b694526a26a30234fb17a40581
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 1484204..3221afa 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -186,9 +186,21 @@
          * {@link #commit} will block until all async commits are
          * completed as well as the commit itself.
          *
-         * <p>If you call this from an {@link android.app.Activity},
-         * the base class will wait for any async commits to finish in
-         * its {@link android.app.Activity#onPause}.</p>
+         * <p>As {@link SharedPreferences} instances are singletons within
+         * a process, it's safe to replace any instance of {@link #commit} with
+         * {@link #apply} if you were already ignoring the return value.
+         *
+         * <p>You don't need to worry about Android component
+         * lifecycles and their interaction with <code>apply()</code>
+         * writing to disk.  The framework makes sure in-flight disk
+         * writes from <code>apply()</code> complete before switching
+         * states.
+         *
+         * <p class='note'>The SharedPreferences.Editor interface
+         * isn't expected to be implemented directly.  However, if you
+         * previously did implement it and are now getting errors
+         * about missing <code>apply()</code>, you can simply call
+         * {@link #commit} from <code>apply()</code>.
          */
         void apply();
     }
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index dde6493..36d676a 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1195,7 +1195,14 @@
 
     private void tryCommit(SharedPreferences.Editor editor) {
         if (mPreferenceManager.shouldCommit()) {
-            editor.apply();
+            try {
+                editor.apply();
+            } catch (AbstractMethodError unused) {
+                // The app injected its own pre-Gingerbread
+                // SharedPreferences.Editor implementation without
+                // an apply method.
+                editor.commit();
+            }
         }
     }
     
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fa83897..e44a090 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -443,7 +443,16 @@
             pm.setSharedPreferencesMode(sharedPreferencesMode);
             pm.inflateFromResource(context, resId, null);
 
-            defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).apply();
+            SharedPreferences.Editor editor =
+                    defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
+            try {
+                editor.apply();
+            } catch (AbstractMethodError unused) {
+                // The app injected its own pre-Gingerbread
+                // SharedPreferences.Editor implementation without
+                // an apply method.
+                editor.commit();
+            }
         }
     }
     
@@ -478,15 +487,21 @@
     boolean shouldCommit() {
         return !mNoCommit;
     }
-    
+
     private void setNoCommit(boolean noCommit) {
         if (!noCommit && mEditor != null) {
-            mEditor.apply();
+            try {
+                mEditor.apply();
+            } catch (AbstractMethodError unused) {
+                // The app injected its own pre-Gingerbread
+                // SharedPreferences.Editor implementation without
+                // an apply method.
+                mEditor.commit();
+            }
         }
-        
         mNoCommit = noCommit;
     }
-    
+
     /**
      * Returns the activity that shows the preferences. This is useful for doing
      * managed queries, but in most cases the use of {@link #getContext()} is