1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 package com.android.settings.display;
15 
16 import android.app.settings.SettingsEnums;
17 import android.content.ContentResolver;
18 import android.content.Context;
19 import android.database.ContentObserver;
20 import android.graphics.drawable.Drawable;
21 import android.hardware.display.ColorDisplayManager;
22 import android.net.Uri;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.provider.SearchIndexableResource;
26 
27 import android.provider.Settings.Secure;
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.PreferenceScreen;
30 
31 import com.android.settings.R;
32 import com.android.settings.search.BaseSearchIndexProvider;
33 import com.android.settings.search.Indexable;
34 import com.android.settings.widget.RadioButtonPickerFragment;
35 import com.android.settingslib.search.SearchIndexable;
36 import com.android.settingslib.widget.CandidateInfo;
37 import com.android.settingslib.widget.LayoutPreference;
38 
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 
43 @SuppressWarnings("WeakerAccess")
44 @SearchIndexable
45 public class ColorModePreferenceFragment extends RadioButtonPickerFragment {
46 
47     @VisibleForTesting
48     static final String KEY_COLOR_MODE_NATURAL = "color_mode_natural";
49     @VisibleForTesting
50     static final String KEY_COLOR_MODE_BOOSTED = "color_mode_boosted";
51     @VisibleForTesting
52     static final String KEY_COLOR_MODE_SATURATED = "color_mode_saturated";
53     @VisibleForTesting
54     static final String KEY_COLOR_MODE_AUTOMATIC = "color_mode_automatic";
55 
56     private ContentObserver mContentObserver;
57     private ColorDisplayManager mColorDisplayManager;
58 
59     @Override
onAttach(Context context)60     public void onAttach(Context context) {
61         super.onAttach(context);
62 
63         mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
64 
65         final ContentResolver cr = context.getContentResolver();
66         mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
67             @Override
68             public void onChange(boolean selfChange, Uri uri) {
69                 super.onChange(selfChange, uri);
70                 if (ColorDisplayManager.areAccessibilityTransformsEnabled(getContext())) {
71                     // Color modes are not configurable when Accessibility transforms are enabled.
72                     // Close this fragment in that case.
73                     getActivity().finish();
74                 }
75             }
76         };
77         cr.registerContentObserver(
78                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
79                 false /* notifyForDescendants */, mContentObserver, mUserId);
80         cr.registerContentObserver(
81                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
82                 false /* notifyForDescendants */, mContentObserver, mUserId);
83     }
84 
85     @Override
onDetach()86     public void onDetach() {
87         super.onDetach();
88         if (mContentObserver != null) {
89             getContext().getContentResolver().unregisterContentObserver(mContentObserver);
90             mContentObserver = null;
91         }
92     }
93 
94     @Override
getPreferenceScreenResId()95     protected int getPreferenceScreenResId() {
96         return R.xml.color_mode_settings;
97     }
98 
99     @VisibleForTesting
configureAndInstallPreview(LayoutPreference preview, PreferenceScreen screen)100     void configureAndInstallPreview(LayoutPreference preview, PreferenceScreen screen) {
101         preview.setSelectable(false);
102         screen.addPreference(preview);
103     }
104 
105     @Override
addStaticPreferences(PreferenceScreen screen)106     protected void addStaticPreferences(PreferenceScreen screen) {
107         final LayoutPreference preview = new LayoutPreference(screen.getContext(),
108                 R.layout.color_mode_preview);
109         configureAndInstallPreview(preview, screen);
110     }
111 
112     @Override
getCandidates()113     protected List<? extends CandidateInfo> getCandidates() {
114         final Context c = getContext();
115         final int[] availableColorModes = c.getResources().getIntArray(
116                 com.android.internal.R.array.config_availableColorModes);
117 
118         List<ColorModeCandidateInfo> candidates = new ArrayList<>();
119         if (availableColorModes != null) {
120             for (int colorMode : availableColorModes) {
121                 if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
122                     candidates.add(new ColorModeCandidateInfo(
123                                 c.getText(R.string.color_mode_option_natural),
124                                 KEY_COLOR_MODE_NATURAL, true /* enabled */));
125                 } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
126                     candidates.add(new ColorModeCandidateInfo(
127                                 c.getText(R.string.color_mode_option_boosted),
128                                 KEY_COLOR_MODE_BOOSTED, true /* enabled */));
129                 } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
130                     candidates.add(new ColorModeCandidateInfo(
131                                 c.getText(R.string.color_mode_option_saturated),
132                                 KEY_COLOR_MODE_SATURATED, true /* enabled */));
133                 } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
134                     candidates.add(new ColorModeCandidateInfo(
135                                 c.getText(R.string.color_mode_option_automatic),
136                                 KEY_COLOR_MODE_AUTOMATIC, true /* enabled */));
137                 }
138             }
139         }
140         return candidates;
141     }
142 
143     @Override
getDefaultKey()144     protected String getDefaultKey() {
145         final int colorMode = mColorDisplayManager.getColorMode();
146         if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
147             return KEY_COLOR_MODE_AUTOMATIC;
148         } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
149             return KEY_COLOR_MODE_SATURATED;
150         } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
151             return KEY_COLOR_MODE_BOOSTED;
152         }
153         return KEY_COLOR_MODE_NATURAL;
154     }
155 
156     @Override
setDefaultKey(String key)157     protected boolean setDefaultKey(String key) {
158         switch (key) {
159             case KEY_COLOR_MODE_NATURAL:
160                 mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
161                 break;
162             case KEY_COLOR_MODE_BOOSTED:
163                 mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
164                 break;
165             case KEY_COLOR_MODE_SATURATED:
166                 mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
167                 break;
168             case KEY_COLOR_MODE_AUTOMATIC:
169                 mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
170                 break;
171         }
172         return true;
173     }
174 
175     @Override
getMetricsCategory()176     public int getMetricsCategory() {
177         return SettingsEnums.COLOR_MODE_SETTINGS;
178     }
179 
180     @VisibleForTesting
181     static class ColorModeCandidateInfo extends CandidateInfo {
182         private final CharSequence mLabel;
183         private final String mKey;
184 
ColorModeCandidateInfo(CharSequence label, String key, boolean enabled)185         ColorModeCandidateInfo(CharSequence label, String key, boolean enabled) {
186             super(enabled);
187             mLabel = label;
188             mKey = key;
189         }
190 
191         @Override
loadLabel()192         public CharSequence loadLabel() {
193             return mLabel;
194         }
195 
196         @Override
loadIcon()197         public Drawable loadIcon() {
198             return null;
199         }
200 
201         @Override
getKey()202         public String getKey() {
203             return mKey;
204         }
205     }
206 
207     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
208             new BaseSearchIndexProvider() {
209                 @Override
210                 public List<SearchIndexableResource> getXmlResourcesToIndex(
211                         Context context, boolean enabled) {
212                     final SearchIndexableResource sir = new SearchIndexableResource(context);
213                     sir.xmlResId = R.xml.color_mode_settings;
214                     return Arrays.asList(sir);
215                 }
216 
217                 @Override
218                 protected boolean isPageSearchEnabled(Context context) {
219                     final int[] availableColorModes = context.getResources().getIntArray(
220                             com.android.internal.R.array.config_availableColorModes);
221                     return availableColorModes != null && availableColorModes.length > 0
222                             && !ColorDisplayManager.areAccessibilityTransformsEnabled(context);
223                 }
224             };
225 }
226