1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.customization.model.themedicon;
17 
18 import android.content.ContentResolver;
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.os.Handler;
23 import android.os.Looper;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.customization.module.CustomizationPreferences;
28 import com.android.themepicker.R;
29 import com.android.wallpaper.module.InjectorProvider;
30 
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 
34 /**
35  * Retrieves the themed icon switch by {@link ContentResolver} from the current launcher
36  */
37 public class ThemedIconSwitchProvider {
38 
39     private static ThemedIconSwitchProvider sThemedIconSwitchProvider;
40 
41     private static final String ICON_THEMED = "icon_themed";
42     private static final String COL_ICON_THEMED_VALUE = "boolean_value";
43     private static final int ENABLED = 1;
44     private static final int RESULT_SUCCESS = 1;
45 
46     private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
47     private final ContentResolver mContentResolver;
48     private final ThemedIconUtils mThemedIconUtils;
49     private final CustomizationPreferences mCustomizationPreferences;
50 
51     /** Callback for the themed icon enabled state fetching result. */
52     public interface FetchThemedIconEnabledCallback {
53         /** Gets called when the result is available. */
onResult(boolean isEnabled)54         void onResult(boolean isEnabled);
55     }
56 
57     /** Returns the {@link ThemedIconSwitchProvider} instance. */
getInstance(Context context)58     public static ThemedIconSwitchProvider getInstance(Context context) {
59         if (sThemedIconSwitchProvider == null) {
60             Context appContext = context.getApplicationContext();
61             sThemedIconSwitchProvider = new ThemedIconSwitchProvider(
62                     appContext.getContentResolver(),
63                     new ThemedIconUtils(appContext,
64                             appContext.getString(R.string.themed_icon_metadata_key)),
65                     (CustomizationPreferences) InjectorProvider.getInjector()
66                             .getPreferences(appContext));
67         }
68         return sThemedIconSwitchProvider;
69     }
70 
ThemedIconSwitchProvider(ContentResolver contentResolver, ThemedIconUtils themedIconUtils, CustomizationPreferences customizationPreferences)71     private ThemedIconSwitchProvider(ContentResolver contentResolver,
72             ThemedIconUtils themedIconUtils, CustomizationPreferences customizationPreferences) {
73         mContentResolver = contentResolver;
74         mThemedIconUtils = themedIconUtils;
75         mCustomizationPreferences = customizationPreferences;
76     }
77 
78     /** Returns {@code true} if themed icon feature is available. */
isThemedIconAvailable()79     public boolean isThemedIconAvailable() {
80         return mThemedIconUtils.isThemedIconAvailable();
81     }
82 
83     /** Gets the themed icon feature enabled state from SharedPreferences. */
isThemedIconEnabled()84     public boolean isThemedIconEnabled() {
85         return mCustomizationPreferences.getThemedIconEnabled();
86     }
87 
88     /**
89      * Fetches the themed icon feature enabled state and stores in SharedPreferences, or returns the
90      * SharedPreferences result if the fetching failed.
91      */
fetchThemedIconEnabled(@ullable FetchThemedIconEnabledCallback callback)92     public void fetchThemedIconEnabled(@Nullable FetchThemedIconEnabledCallback callback) {
93         mExecutorService.submit(() -> {
94             try (Cursor cursor = mContentResolver.query(
95                     mThemedIconUtils.getUriForPath(ICON_THEMED), /* projection= */ null,
96                     /* selection= */ null, /* selectionArgs= */ null, /* sortOrder= */ null)) {
97                 if (cursor != null && cursor.moveToNext()) {
98                     boolean isEnabled = cursor.getInt(cursor.getColumnIndex(COL_ICON_THEMED_VALUE))
99                             == ENABLED;
100                     if (mCustomizationPreferences.getThemedIconEnabled() != isEnabled) {
101                         mCustomizationPreferences.setThemedIconEnabled(isEnabled);
102                     }
103                     if (callback != null) {
104                         postMainThread(() -> callback.onResult(isEnabled));
105                     }
106                     return;
107                 }
108             }
109             if (callback != null) {
110                 postMainThread(
111                         () -> callback.onResult(mCustomizationPreferences.getThemedIconEnabled()));
112             }
113         });
114     }
115 
116     /**
117      * Enables themed icon feature or not.
118      *
119      * <p>The value would also be stored in SharedPreferences.
120      */
setThemedIconEnabled(boolean enabled)121     public void setThemedIconEnabled(boolean enabled) {
122         mExecutorService.submit(() -> {
123             ContentValues values = new ContentValues();
124             values.put(COL_ICON_THEMED_VALUE, enabled);
125             int result = mContentResolver.update(mThemedIconUtils.getUriForPath(ICON_THEMED),
126                     values, /* where= */ null, /* selectionArgs= */ null);
127             if (result == RESULT_SUCCESS) {
128                 mCustomizationPreferences.setThemedIconEnabled(enabled);
129             }
130         });
131     }
132 
postMainThread(Runnable runnable)133     private void postMainThread(Runnable runnable) {
134         new Handler(Looper.getMainLooper()).post(runnable);
135     }
136 }
137