Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/src/com/android/customization/model/themedicon/ThemedIconSectionController.java b/src/com/android/customization/model/themedicon/ThemedIconSectionController.java
index 9ec5c2c..c097b6b 100644
--- a/src/com/android/customization/model/themedicon/ThemedIconSectionController.java
+++ b/src/com/android/customization/model/themedicon/ThemedIconSectionController.java
@@ -25,9 +25,6 @@
 import com.android.wallpaper.model.CustomizationSectionController;
 import com.android.wallpaper.model.WorkspaceViewModel;
 
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
 /** The {@link CustomizationSectionController} for themed icon section. */
 public class ThemedIconSectionController implements
         CustomizationSectionController<ThemedIconSectionView> {
@@ -35,7 +32,6 @@
     private final ThemedIconSwitchProvider mThemedIconOptionsProvider;
     private final WorkspaceViewModel mWorkspaceViewModel;
 
-    private static ExecutorService sExecutorService = Executors.newSingleThreadExecutor();
 
     public ThemedIconSectionController(ThemedIconSwitchProvider themedIconOptionsProvider,
             WorkspaceViewModel workspaceViewModel) {
@@ -54,11 +50,8 @@
                 (ThemedIconSectionView) LayoutInflater.from(context).inflate(
                         R.layout.themed_icon_section_view, /* root= */ null);
         themedIconColorSectionView.setViewListener(this::onViewActivated);
-        sExecutorService.submit(() -> {
-            boolean themedIconEnabled = mThemedIconOptionsProvider.fetchThemedIconEnabled();
-            themedIconColorSectionView.post(() ->
-                    themedIconColorSectionView.getSwitch().setChecked(themedIconEnabled));
-        });
+        mThemedIconOptionsProvider.fetchThemedIconEnabled(
+                enabled -> themedIconColorSectionView.getSwitch().setChecked(enabled));
         return themedIconColorSectionView;
     }
 
diff --git a/src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java b/src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java
index 0385bbb..9acd319 100644
--- a/src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java
+++ b/src/com/android/customization/model/themedicon/ThemedIconSwitchProvider.java
@@ -19,49 +19,118 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.os.Handler;
+import android.os.Looper;
 
-import androidx.annotation.WorkerThread;
+import androidx.annotation.Nullable;
+
+import com.android.customization.module.CustomizationPreferences;
+import com.android.wallpaper.R;
+import com.android.wallpaper.module.InjectorProvider;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * Retrieves the themed icon switch by {@link ContentResolver} from the current launcher
  */
 public class ThemedIconSwitchProvider {
 
+    private static ThemedIconSwitchProvider sThemedIconSwitchProvider;
+
     private static final String ICON_THEMED = "icon_themed";
-    private static final int ENABLED = 1;
     private static final String COL_ICON_THEMED_VALUE = "boolean_value";
+    private static final int ENABLED = 1;
+    private static final int RESULT_SUCCESS = 1;
 
-    private final Context mContext;
+    private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
+    private final ContentResolver mContentResolver;
     private final ThemedIconUtils mThemedIconUtils;
+    private final CustomizationPreferences mCustomizationPreferences;
 
-    public ThemedIconSwitchProvider(Context context, ThemedIconUtils themedIconUtils) {
-        mContext = context;
-        mThemedIconUtils = themedIconUtils;
+    /** Callback for the themed icon enabled state fetching result. */
+    public interface FetchThemedIconEnabledCallback {
+        /** Gets called when the result is available. */
+        void onResult(boolean isEnabled);
     }
 
+    /** Returns the {@link ThemedIconSwitchProvider} instance. */
+    public static ThemedIconSwitchProvider getInstance(Context context) {
+        if (sThemedIconSwitchProvider == null) {
+            Context appContext = context.getApplicationContext();
+            sThemedIconSwitchProvider = new ThemedIconSwitchProvider(
+                    appContext.getContentResolver(),
+                    new ThemedIconUtils(appContext,
+                            appContext.getString(R.string.themed_icon_metadata_key)),
+                    (CustomizationPreferences) InjectorProvider.getInjector()
+                            .getPreferences(appContext));
+        }
+        return sThemedIconSwitchProvider;
+    }
+
+    private ThemedIconSwitchProvider(ContentResolver contentResolver,
+            ThemedIconUtils themedIconUtils, CustomizationPreferences customizationPreferences) {
+        mContentResolver = contentResolver;
+        mThemedIconUtils = themedIconUtils;
+        mCustomizationPreferences = customizationPreferences;
+    }
+
+    /** Returns {@code true} if themed icon feature is available. */
     public boolean isThemedIconAvailable() {
         return mThemedIconUtils.isThemedIconAvailable();
     }
 
-    @WorkerThread
-    public boolean fetchThemedIconEnabled() {
-        ContentResolver contentResolver = mContext.getContentResolver();
-        try (Cursor cursor = contentResolver.query(
-                mThemedIconUtils.getUriForPath(ICON_THEMED), /* projection= */
-                null, /* selection= */ null, /* selectionArgs= */ null, /* sortOrder= */ null)) {
-            if (cursor != null && cursor.moveToNext()) {
-                int themedIconEnabled = cursor.getInt(cursor.getColumnIndex(COL_ICON_THEMED_VALUE));
-                return themedIconEnabled == ENABLED;
-            }
-        }
-        return false;
+    /** Gets the themed icon feature enabled state from SharedPreferences. */
+    public boolean isThemedIconEnabled() {
+        return mCustomizationPreferences.getThemedIconEnabled();
     }
 
-    protected int setThemedIconEnabled(boolean enabled) {
-        ContentValues values = new ContentValues();
-        values.put(COL_ICON_THEMED_VALUE, enabled);
-        return mContext.getContentResolver().update(
-                mThemedIconUtils.getUriForPath(ICON_THEMED), values,
-                /* where= */ null, /* selectionArgs= */ null);
+    /**
+     * Fetches the themed icon feature enabled state and stores in SharedPreferences, or returns the
+     * SharedPreferences result if the fetching failed.
+     */
+    public void fetchThemedIconEnabled(@Nullable FetchThemedIconEnabledCallback callback) {
+        mExecutorService.submit(() -> {
+            try (Cursor cursor = mContentResolver.query(
+                    mThemedIconUtils.getUriForPath(ICON_THEMED), /* projection= */ null,
+                    /* selection= */ null, /* selectionArgs= */ null, /* sortOrder= */ null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    boolean isEnabled = cursor.getInt(cursor.getColumnIndex(COL_ICON_THEMED_VALUE))
+                            == ENABLED;
+                    if (mCustomizationPreferences.getThemedIconEnabled() != isEnabled) {
+                        mCustomizationPreferences.setThemedIconEnabled(isEnabled);
+                    }
+                    if (callback != null) {
+                        postMainThread(() -> callback.onResult(isEnabled));
+                    }
+                    return;
+                }
+            }
+            if (callback != null) {
+                postMainThread(
+                        () -> callback.onResult(mCustomizationPreferences.getThemedIconEnabled()));
+            }
+        });
+    }
+
+    /**
+     * Enables themed icon feature or not.
+     *
+     * <p>The value would also be stored in SharedPreferences.
+     */
+    protected void setThemedIconEnabled(boolean enabled) {
+        mExecutorService.submit(() -> {
+            ContentValues values = new ContentValues();
+            values.put(COL_ICON_THEMED_VALUE, enabled);
+            int result = mContentResolver.update(mThemedIconUtils.getUriForPath(ICON_THEMED),
+                    values, /* where= */ null, /* selectionArgs= */ null);
+            if (result == RESULT_SUCCESS) {
+                mCustomizationPreferences.setThemedIconEnabled(enabled);
+            }
+        });
+    }
+
+    private void postMainThread(Runnable runnable) {
+        new Handler(Looper.getMainLooper()).post(runnable);
     }
 }
diff --git a/src/com/android/customization/module/CustomizationPreferences.java b/src/com/android/customization/module/CustomizationPreferences.java
index d32143a..0df3ff9 100644
--- a/src/com/android/customization/module/CustomizationPreferences.java
+++ b/src/com/android/customization/module/CustomizationPreferences.java
@@ -21,6 +21,7 @@
 
     String KEY_CUSTOM_THEME= "themepicker_custom_theme";
     String KEY_VISITED_PREFIX = "themepicker_visited_";
+    String KEY_THEMED_ICON_ENABLED = "themepicker_themed_icon_enabled";
 
     String getSerializedCustomThemes();
 
@@ -29,4 +30,8 @@
     boolean getTabVisited(String id);
 
     void setTabVisited(String id);
+
+    boolean getThemedIconEnabled();
+
+    void setThemedIconEnabled(boolean enabled);
 }
diff --git a/src/com/android/customization/module/DefaultCustomizationPreferences.java b/src/com/android/customization/module/DefaultCustomizationPreferences.java
index e6b4d05..4af402f 100644
--- a/src/com/android/customization/module/DefaultCustomizationPreferences.java
+++ b/src/com/android/customization/module/DefaultCustomizationPreferences.java
@@ -46,4 +46,14 @@
     public void setTabVisited(String id) {
         mSharedPrefs.edit().putBoolean(KEY_VISITED_PREFIX + id, true).apply();
     }
+
+    @Override
+    public boolean getThemedIconEnabled() {
+        return mSharedPrefs.getBoolean(KEY_THEMED_ICON_ENABLED, false);
+    }
+
+    @Override
+    public void setThemedIconEnabled(boolean enabled) {
+        mSharedPrefs.edit().putBoolean(KEY_THEMED_ICON_ENABLED, enabled).apply();
+    }
 }
diff --git a/src/com/android/customization/module/DefaultCustomizationSections.java b/src/com/android/customization/module/DefaultCustomizationSections.java
index db9218f..eb5296d 100644
--- a/src/com/android/customization/module/DefaultCustomizationSections.java
+++ b/src/com/android/customization/module/DefaultCustomizationSections.java
@@ -11,8 +11,6 @@
 import com.android.customization.model.mode.DarkModeSectionController;
 import com.android.customization.model.themedicon.ThemedIconSectionController;
 import com.android.customization.model.themedicon.ThemedIconSwitchProvider;
-import com.android.customization.model.themedicon.ThemedIconUtils;
-import com.android.wallpaper.R;
 import com.android.wallpaper.model.CustomizationSectionController;
 import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController;
 import com.android.wallpaper.model.PermissionRequester;
@@ -49,9 +47,7 @@
 
         // Themed app icon section.
         sectionControllers.add(new ThemedIconSectionController(
-                new ThemedIconSwitchProvider(activity, new ThemedIconUtils(activity,
-                        activity.getString(R.string.themed_icon_metadata_key))),
-                workspaceViewModel));
+                ThemedIconSwitchProvider.getInstance(activity), workspaceViewModel));
 
         // App grid section.
         sectionControllers.add(new GridSectionController(