Settings: Configurable 0, 90, 180 and 270 degree rotation [2/2]

- Checkboxes are a thing of the past, Switches is where is at! #YOLOHOLO am I right?

@jhenrique09 edits: Add preference controller to show proper summary

Change-Id: I8301125e38c0c4f7d1d9dec6082a58901509ce11
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 3ed5052..ba345ff 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -54,4 +54,15 @@
     <!-- Hotspot extras -->
     <string name="tethering_allow_vpn_upstreams_title">Allow clients to use VPNs</string>
     <string name="tethering_allow_vpn_upstreams_summary">Permit hotspot clients to use this device\u2019s VPN connections for upstream connectivity</string>
+
+    <!-- Display : Rotation -->
+    <string name="display_rotation_title">Rotation settings</string>
+    <string name="display_rotation_enabled">Auto-rotation is enabled</string>
+    <string name="display_rotation_disabled">Auto-rotation is disabled</string>
+    <string name="display_rotation_unit">degrees</string>
+    <string name="display_rotation_category_title">Rotation modes</string>
+    <string name="display_rotation_0_title">0 degrees</string>
+    <string name="display_rotation_90_title">90 degrees</string>
+    <string name="display_rotation_180_title">180 degrees</string>
+    <string name="display_rotation_270_title">270 degrees</string>
 </resources>
diff --git a/res/xml/display_rotation.xml b/res/xml/display_rotation.xml
new file mode 100644
index 0000000..e6a66d3
--- /dev/null
+++ b/res/xml/display_rotation.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+        android:title="@string/display_rotation_title"
+        xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+    <SwitchPreference
+        android:key="accelerometer"
+        android:title="@string/accelerometer_title" />
+
+    <PreferenceCategory
+        android:key="display_rotation_category"
+        android:title="@string/display_rotation_category_title" />
+
+        <SwitchPreference
+            android:key="display_rotation_0"
+            android:title="@string/display_rotation_0_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_90"
+            android:title="@string/display_rotation_90_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_180"
+            android:title="@string/display_rotation_180_title"
+            android:dependency="accelerometer" />
+
+        <SwitchPreference
+            android:key="display_rotation_270"
+            android:title="@string/display_rotation_270_title"
+            android:dependency="accelerometer" />
+
+</PreferenceScreen>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 3720708..71919b3 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -121,6 +121,12 @@
             settings:keywords="@string/keywords_auto_rotate"
             settings:controller="com.android.settings.display.AutoRotatePreferenceController"/>
 
+        <Preference
+            android:key="display_rotation"
+            android:fragment="com.android.settings.display.DisplayRotation"
+            android:title="@string/display_rotation_title"
+            settings:controller="com.android.settings.display.DisplayRotationPreferenceController" />
+
         <!--
             Auto-rotation preference that will be shown when device state based auto-rotation
             settings are available.
diff --git a/src/com/android/settings/display/DisplayRotation.java b/src/com/android/settings/display/DisplayRotation.java
new file mode 100644
index 0000000..569dd51
--- /dev/null
+++ b/src/com/android/settings/display/DisplayRotation.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod 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.settings.display;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Bundle;
+import android.os.Handler;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.SwitchPreference;
+import android.provider.Settings;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.RotationPolicy;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+public class DisplayRotation extends SettingsPreferenceFragment implements OnPreferenceChangeListener {
+    private static final String TAG = "DisplayRotation";
+
+    private static final String KEY_ACCELEROMETER = "accelerometer";
+    private static final String ROTATION_0_PREF = "display_rotation_0";
+    private static final String ROTATION_90_PREF = "display_rotation_90";
+    private static final String ROTATION_180_PREF = "display_rotation_180";
+    private static final String ROTATION_270_PREF = "display_rotation_270";
+
+    private SwitchPreference mAccelerometer;
+    private SwitchPreference mRotation0Pref;
+    private SwitchPreference mRotation90Pref;
+    private SwitchPreference mRotation180Pref;
+    private SwitchPreference mRotation270Pref;
+
+    public static final int ROTATION_0_MODE = 1;
+    public static final int ROTATION_90_MODE = 2;
+    public static final int ROTATION_180_MODE = 4;
+    public static final int ROTATION_270_MODE = 8;
+
+    private ContentObserver mAccelerometerRotationObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateAccelerometerRotationSwitch();
+        }
+    };
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.VIEW_UNKNOWN;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        addPreferencesFromResource(R.xml.display_rotation);
+
+        mAccelerometer = findPreference(KEY_ACCELEROMETER);
+        mAccelerometer.setPersistent(false);
+
+        mRotation0Pref = findPreference(ROTATION_0_PREF);
+        mRotation90Pref = findPreference(ROTATION_90_PREF);
+        mRotation180Pref = findPreference(ROTATION_180_PREF);
+        mRotation270Pref = findPreference(ROTATION_270_PREF);
+
+        int mode = Settings.System.getInt(getContentResolver(),
+                        Settings.System.ACCELEROMETER_ROTATION_ANGLES,
+                        ROTATION_0_MODE|ROTATION_90_MODE|ROTATION_270_MODE);
+
+        mRotation0Pref.setChecked((mode & ROTATION_0_MODE) != 0);
+        mRotation90Pref.setChecked((mode & ROTATION_90_MODE) != 0);
+        mRotation180Pref.setChecked((mode & ROTATION_180_MODE) != 0);
+        mRotation270Pref.setChecked((mode & ROTATION_270_MODE) != 0);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateState();
+
+        getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), true,
+                mAccelerometerRotationObserver);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        getContentResolver().unregisterContentObserver(mAccelerometerRotationObserver);
+    }
+
+    private void updateState() {
+        updateAccelerometerRotationSwitch();
+    }
+
+    private void updateAccelerometerRotationSwitch() {
+        mAccelerometer.setChecked(!RotationPolicy.isRotationLocked(getActivity()));
+    }
+
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        return false;
+    }
+
+    public boolean onPreferenceTreeClick(Preference preference) {
+        if (preference == mAccelerometer) {
+            RotationPolicy.setRotationLockForAccessibility(getActivity(),
+                !mAccelerometer.isChecked(), /* caller= */ "DisplayRotation");
+        } else if (preference == mRotation0Pref ||
+                preference == mRotation90Pref ||
+                preference == mRotation180Pref ||
+                preference == mRotation270Pref) {
+            int mode = 0;
+            if (mRotation0Pref.isChecked())
+                mode |= ROTATION_0_MODE;
+            if (mRotation90Pref.isChecked())
+                mode |= ROTATION_90_MODE;
+            if (mRotation180Pref.isChecked())
+                mode |= ROTATION_180_MODE;
+            if (mRotation270Pref.isChecked())
+                mode |= ROTATION_270_MODE;
+            if (mode == 0) {
+                mode |= ROTATION_0_MODE;
+                mRotation0Pref.setChecked(true);
+            }
+            Settings.System.putInt(getActivity().getApplicationContext().getContentResolver(),
+                    Settings.System.ACCELEROMETER_ROTATION_ANGLES, mode);
+            return true;
+        }
+        return super.onPreferenceTreeClick(preference);
+    }
+}
diff --git a/src/com/android/settings/display/DisplayRotationPreferenceController.java b/src/com/android/settings/display/DisplayRotationPreferenceController.java
new file mode 100644
index 0000000..31713b7
--- /dev/null
+++ b/src/com/android/settings/display/DisplayRotationPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.settings.display;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+
+import com.android.internal.view.RotationPolicy;
+
+import com.android.settings.R;
+
+public class DisplayRotationPreferenceController extends BasePreferenceController implements
+        PreferenceControllerMixin {
+
+    public DisplayRotationPreferenceController(Context context, String preferenceKey) {
+        super(context, preferenceKey);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        String summary = RotationPolicy.isRotationLocked(mContext) ?
+                            mContext.getString(R.string.display_rotation_disabled) :
+                            mContext.getString(R.string.display_rotation_enabled);
+        preference.setSummary(summary);
+    }
+}