Use a broadcast receiver instead of a settings observer.

Settings observer doesn't work if a setting is modified in another
process, hence we instead register a receiver which listens for a signal
from the settings process that the rotation preference has changed.

Change-Id: I570e3c67bb64a32347e84ca00a8ac31d9010eac3
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fce4691..f9f5fc2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -45,6 +45,10 @@
         android:protectionLevel="signature"
         />
     <permission
+        android:name="com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS"
+        android:protectionLevel="signature"
+        />
+    <permission
         android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST"
         android:protectionLevel="signatureOrSystem" />
 
@@ -62,6 +66,7 @@
     <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" />
+    <uses-permission android:name="com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS" />
     <uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" />
 
     <application
@@ -152,7 +157,8 @@
         <activity
             android:name="com.android.launcher3.SettingsActivity"
             android:label="@string/settings_button_text"
-            android:autoRemoveFromRecents="true">
+            android:autoRemoveFromRecents="true"
+            android:process=":settings_process">
         </activity>
 
         <!-- Debugging tools -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 440a537..305c310 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -27,6 +27,9 @@
     <!-- Permission to receive the com.android.launcher3.action.LAUNCH intent -->
     <string name="receive_launch_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS</string>
 
+    <!-- Permission to receive the com.android.launcher3.SCREEN_ORIENTATION_PREF_CHANGED intent -->
+    <string name="receive_update_orientation_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_UPDATE_ORIENTATION_BROADCASTS</string>
+
     <!-- Permission to receive the com.android.launcher3.action.FIRST_LOAD_COMPLETE intent -->
     <string name="receive_first_load_broadcast_permission" translatable="false">com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST</string>
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index dc63a76..6dfe0eb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -403,22 +403,34 @@
     FocusIndicatorView mFocusHandler;
 
     @Thunk boolean mRotationEnabled = false;
-    private boolean mPreferenceObserverRegistered = false;
+    private boolean mScreenOrientationSettingReceiverRegistered = false;
 
-    final private SharedPreferences.OnSharedPreferenceChangeListener mSettingsObserver =
-            new SharedPreferences.OnSharedPreferenceChangeListener() {
-        @Override
-        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-            if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(key)) {
-                if (mRotationEnabled = sharedPreferences.getBoolean(
-                        Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false)) {
-                    unlockScreenOrientation(true);
-                } else {
-                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+    final private BroadcastReceiver mScreenOrientationSettingReceiver =
+            new BroadcastReceiver() {
+                @Thunk Runnable mUpdateOrientationRunnable = new Runnable() {
+                    public void run() {
+                        setOrientation();
+                    }
+                };
+
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mRotationEnabled = intent.getBooleanExtra(
+                            Utilities.SCREEN_ROTATION_SETTING_EXTRA, false);
+                    if (!waitUntilResume(mUpdateOrientationRunnable, true)) {
+                        setOrientation();
+                    }
                 }
-            }
+            };
+
+    @Thunk void setOrientation() {
+        if (mRotationEnabled) {
+            unlockScreenOrientation(true);
+        } else {
+            setRequestedOrientation(
+                    ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
         }
-    };
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -520,16 +532,18 @@
         // In case we are on a device with locked rotation, we should look at preferences to check
         // if the user has specifically allowed rotation.
         if (!mRotationEnabled) {
-            getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
-                    Context.MODE_MULTI_PROCESS).registerOnSharedPreferenceChangeListener(
-                    mSettingsObserver);
-            mPreferenceObserverRegistered = true;
+            String updateOrientationBroadcastPermission = getResources().getString(
+                    R.string.receive_update_orientation_broadcasts_permission);
+            registerReceiver(mScreenOrientationSettingReceiver,
+                    new IntentFilter(Utilities.SCREEN_ROTATION_SETTING_INTENT),
+                    updateOrientationBroadcastPermission, null);
+            mScreenOrientationSettingReceiverRegistered = true;
             mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
         }
 
         // On large interfaces, or on devices that a user has specifically enabled screen rotation,
         // we want the screen to auto-rotate based on the current orientation
-        unlockScreenOrientation(true);
+        setOrientation();
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
@@ -2016,11 +2030,9 @@
     public void onDestroy() {
         super.onDestroy();
 
-        if (mPreferenceObserverRegistered) {
-            getSharedPreferences(LauncherFiles.ROTATION_PREF_FILE,
-                    Context.MODE_MULTI_PROCESS).unregisterOnSharedPreferenceChangeListener(
-                    mSettingsObserver);
-            mPreferenceObserverRegistered = false;
+        if (mScreenOrientationSettingReceiverRegistered) {
+            unregisterReceiver(mScreenOrientationSettingReceiver);
+            mScreenOrientationSettingReceiverRegistered = false;
         }
 
         // Remove all pending runnables
@@ -3663,7 +3675,7 @@
      *
      * @return {@code true} if we are currently paused. The caller might be able to skip some work
      */
-    private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
+    @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
         if (mPaused) {
             if (LOGD) Log.d(TAG, "Deferring update until onResume");
             if (deletePreviousRunnables) {
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index a1da1b6..27763f5 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -18,12 +18,14 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
+import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
 
 /**
- * Settings activity for Launcher. Currently implements the following setting:
- * LockToPortrait
+ * Settings activity for Launcher. Currently implements the following setting: Allow rotation
  */
 public class SettingsActivity extends Activity {
     @Override
@@ -41,13 +43,25 @@
      */
     @SuppressWarnings("WeakerAccess")
     public static class LauncherSettingsFragment extends PreferenceFragment {
-
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE);
+            getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
             getPreferenceManager().setSharedPreferencesName(LauncherFiles.ROTATION_PREF_FILE);
             addPreferencesFromResource(R.xml.launcher_preferences);
         }
+
+        @Override
+        public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+                                             Preference preference) {
+            boolean allowRotation = getPreferenceManager().getSharedPreferences().getBoolean(
+                    Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false);
+            Intent rotationSetting = new Intent(Utilities.SCREEN_ROTATION_SETTING_INTENT);
+            String launchBroadcastPermission = getResources().getString(
+                            R.string.receive_update_orientation_broadcasts_permission);
+            rotationSetting.putExtra(Utilities.SCREEN_ROTATION_SETTING_EXTRA, allowRotation);
+            getActivity().sendBroadcast(rotationSetting, launchBroadcastPermission);
+            return true;
+        }
     }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index cffcd34..b267f75 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -93,6 +93,9 @@
     private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
 
     public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+    public static final String SCREEN_ROTATION_SETTING_INTENT =
+            "come.android.launcher3.SCREEN_ORIENTATION_PREF_CHANGED";
+    public static final String SCREEN_ROTATION_SETTING_EXTRA = "screenRotationPref";
 
     public static boolean isPropertyEnabled(String propertyName) {
         return Log.isLoggable(propertyName, Log.VERBOSE);