[1/2] OmniGears: add omni theme selector

Change-Id: I14b6d31f35db391450b2e2f6dc60ff593e8a6afb
diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml
index f981518..96a1052 100644
--- a/res/values/custom_strings.xml
+++ b/res/values/custom_strings.xml
@@ -441,8 +441,6 @@
 
     <!-- OMS -->
     <string name="theming_title">Theming</string>
-    <string name="oms_app_title">Substratum theme engine</string>
-    <string name="oms_app_summary">Start Substratum experience</string>
 
     <string name="status_bar_ime_notification_title">Show IME notification</string>
     <string name="status_bar_ime_notification_summary">If navigation bar is not available</string>
@@ -608,8 +606,6 @@
 
     <string name="logcat_app_title">MatLog</string>
     <string name="logcat_app_summary">Start app to collect logs</string>
-    <string name="omni_theme_title">Omni Light/Dark theme</string>
-    <string name="omni_theme_summary">Substratum based theme</string>
 
     <string name="show_dashboard_columns_title">Use columns layout</string>
     <string name="show_dashboard_columns_summary">In settings main page</string>
@@ -637,4 +633,7 @@
     <string name="screen_off_animation_crt">CRT</string>
     <string name="screen_off_animation_scale">Scale</string>
     <string name="screen_off_animation_title">Screen off animation</string>
+
+    <string name="omni_theme_select_title">Omni themes</string>
+    <string name="omni_theme_select_none">Disabled</string>
 </resources>
diff --git a/res/xml/style_settings.xml b/res/xml/style_settings.xml
index 06b8cd7..94971eb 100644
--- a/res/xml/style_settings.xml
+++ b/res/xml/style_settings.xml
@@ -38,6 +38,11 @@
             android:entries="@array/systemui_theme_style_entries"
             android:entryValues="@array/systemui_theme_style_values" />
 
+        <ListPreference
+            android:key="omni_theme_select"
+            android:title="@string/omni_theme_select_title"
+            android:summary="@string/summary_placeholder" />
+
     </PreferenceCategory>
 
     <PreferenceCategory
diff --git a/src/org/omnirom/omnigears/interfacesettings/OmniThemePreferenceController.java b/src/org/omnirom/omnigears/interfacesettings/OmniThemePreferenceController.java
new file mode 100644
index 0000000..346e286
--- /dev/null
+++ b/src/org/omnirom/omnigears/interfacesettings/OmniThemePreferenceController.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2017 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 org.omnirom.omnigears.interfacesettings;
+
+import android.content.Context;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import libcore.util.Objects;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_THEME;
+
+public class OmniThemePreferenceController extends AbstractPreferenceController implements
+        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+
+    private static final String KEY_THEME = "omni_theme_select";
+    private static final String KEY_THEMES_DISABLED = "default";
+    private static final String OMNI_THEME_PREFIX = "org.omnirom.";
+
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
+    private final OverlayManager mOverlayService;
+    private final PackageManager mPackageManager;
+
+    public OmniThemePreferenceController(Context context) {
+        this(context, ServiceManager.getService(Context.OVERLAY_SERVICE) != null
+                ? new OverlayManager() : null);
+    }
+
+    @VisibleForTesting
+    OmniThemePreferenceController(Context context, OverlayManager overlayManager) {
+        super(context);
+        mOverlayService = overlayManager;
+        mPackageManager = context.getPackageManager();
+        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_THEME;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (KEY_THEME.equals(preference.getKey())) {
+            mMetricsFeatureProvider.action(mContext, ACTION_THEME);
+        }
+        return false;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ListPreference pref = (ListPreference) preference;
+        List<String> pkgs = new ArrayList<>(Arrays.asList(getAvailableThemes()));
+        List<CharSequence> labels = new ArrayList<>(pkgs.size());
+        for (String pkg : pkgs) {
+            CharSequence label = null;
+            try {
+                label = mPackageManager.getApplicationInfo(pkg, 0).loadLabel(mPackageManager);
+            } catch (NameNotFoundException e) {
+                label = pkg;
+            }
+            labels.add(label);
+        }
+        labels.add(mContext.getString(R.string.omni_theme_select_none));
+        pkgs.add(KEY_THEMES_DISABLED);
+
+        pref.setEntries(labels.toArray(new CharSequence[labels.size()]));
+        pref.setEntryValues(pkgs.toArray(new String[pkgs.size()]));
+        String theme = getCurrentTheme();
+        CharSequence themeLabel = null;
+
+        if (theme != null) {
+            int i = 0;
+            for (String pkg : pkgs) {
+                if (TextUtils.equals(pkg, theme)) {
+                    themeLabel = labels.get(i);
+                    break;
+                }
+                i++;
+            }
+        }
+
+        if (TextUtils.isEmpty(themeLabel)) {
+            themeLabel = mContext.getString(R.string.omni_theme_select_none);
+            theme = KEY_THEMES_DISABLED;
+        }
+
+        pref.setSummary(themeLabel);
+        pref.setValue(theme);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        String current = getTheme();
+        if (Objects.equal(newValue, current)) {
+            return true;
+        }
+        try {
+            if (newValue.equals(KEY_THEMES_DISABLED)) {
+                disableTheme();
+            } else {
+                mOverlayService.setEnabledExclusive((String) newValue, true, UserHandle.myUserId());
+            }
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isChangeableOverlay(String packageName) {
+        try {
+            PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
+            return pi != null && !pi.isStaticOverlay;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private String getTheme() {
+        try {
+            List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
+                    UserHandle.myUserId());
+            for (int i = 0, size = infos.size(); i < size; i++) {
+                if (infos.get(i).isEnabled() &&
+                        isChangeableOverlay(infos.get(i).packageName)) {
+                    return infos.get(i).packageName;
+                }
+            }
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    private void disableTheme() {
+        try {
+            List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
+                    UserHandle.myUserId());
+            for (int i = 0, size = infos.size(); i < size; i++) {
+                if (infos.get(i).isEnabled() &&
+                        infos.get(i).packageName.startsWith(OMNI_THEME_PREFIX) &&
+                        isChangeableOverlay(infos.get(i).packageName)) {
+                    mOverlayService.setEnabled(infos.get(i).packageName, false, UserHandle.myUserId());
+                }
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (mOverlayService == null) return false;
+        String[] themes = getAvailableThemes();
+        return themes != null && themes.length >= 1;
+    }
+
+
+    @VisibleForTesting
+    String getCurrentTheme() {
+        return getTheme();
+    }
+
+    @VisibleForTesting
+    String[] getAvailableThemes() {
+        try {
+            List<OverlayInfo> infos = mOverlayService.getOverlayInfosForTarget("android",
+                    UserHandle.myUserId());
+            List<String> pkgs = new ArrayList(infos.size());
+            for (int i = 0, size = infos.size(); i < size; i++) {
+                if (infos.get(i).packageName.startsWith(OMNI_THEME_PREFIX) &&
+                        isChangeableOverlay(infos.get(i).packageName)) {
+                    pkgs.add(infos.get(i).packageName);
+                }
+            }
+            return pkgs.toArray(new String[pkgs.size()]);
+        } catch (RemoteException e) {
+        }
+        return new String[0];
+    }
+
+    public static class OverlayManager {
+        private final IOverlayManager mService;
+
+        public OverlayManager() {
+            mService = IOverlayManager.Stub.asInterface(
+                    ServiceManager.getService(Context.OVERLAY_SERVICE));
+        }
+
+        public void setEnabledExclusive(String pkg, boolean enabled, int userId)
+                throws RemoteException {
+            mService.setEnabledExclusive(pkg, enabled, userId);
+        }
+
+        public void setEnabled(String pkg, boolean enabled, int userId)
+                throws RemoteException {
+            mService.setEnabled(pkg, enabled, userId);
+        }
+
+        public List<OverlayInfo> getOverlayInfosForTarget(String target, int userId)
+                throws RemoteException {
+            return mService.getOverlayInfosForTarget(target, userId);
+        }
+    }
+}
diff --git a/src/org/omnirom/omnigears/interfacesettings/StyleSettings.java b/src/org/omnirom/omnigears/interfacesettings/StyleSettings.java
index d1ceb1a..4f0a670 100644
--- a/src/org/omnirom/omnigears/interfacesettings/StyleSettings.java
+++ b/src/org/omnirom/omnigears/interfacesettings/StyleSettings.java
@@ -35,12 +35,13 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.omni.PackageUtils;
 
-import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
+import com.android.settingslib.core.AbstractPreferenceController;
 
 import org.omnirom.omnigears.preference.SystemSettingSwitchPreference;
 import org.omnirom.omnigears.preference.SeekBarPreference;
@@ -51,7 +52,7 @@
 import java.util.List;
 import java.util.Map;
 
-public class StyleSettings extends SettingsPreferenceFragment implements
+public class StyleSettings extends DashboardFragment implements
         Preference.OnPreferenceChangeListener, Indexable {
     private static final String TAG = "StyleSettings";
     private static final String CUSTOM_WALL_BROWSE = "custom_wall_browse";
@@ -84,9 +85,19 @@
     }
 
     @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.style_settings;
+    }
+
+    @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        addPreferencesFromResource(R.xml.style_settings);
+        //addPreferencesFromResource(R.xml.style_settings);
 
         mWallBrowse = findPreference(CUSTOM_WALL_BROWSE);
         mWallBrowse.setEnabled(isBrowseWallsAvailable());
@@ -266,6 +277,13 @@
         }
     }
 
+    @Override
+    protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+        final List<AbstractPreferenceController> controllers = new ArrayList<>();
+        controllers.add(new OmniThemePreferenceController(context));
+        return controllers;
+    }
+
     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
                 @Override