• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 
17 package com.android.settings.development.graphicsdriver;
18 
19 import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
20 import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
21 
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageManager;
26 import android.content.res.Resources;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.provider.Settings;
30 
31 import androidx.annotation.VisibleForTesting;
32 import androidx.preference.ListPreference;
33 import androidx.preference.Preference;
34 import androidx.preference.PreferenceGroup;
35 import androidx.preference.PreferenceScreen;
36 
37 import com.android.settings.R;
38 import com.android.settings.core.BasePreferenceController;
39 import com.android.settingslib.core.lifecycle.LifecycleObserver;
40 import com.android.settingslib.core.lifecycle.events.OnStart;
41 import com.android.settingslib.core.lifecycle.events.OnStop;
42 import com.android.settingslib.development.DevelopmentSettingsEnabler;
43 
44 import java.text.Collator;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Comparator;
49 import java.util.HashSet;
50 import java.util.List;
51 import java.util.Set;
52 
53 /**
54  * Controller of all the per App based list preferences.
55  */
56 public class GraphicsDriverAppPreferenceController extends BasePreferenceController
57         implements Preference.OnPreferenceChangeListener,
58         GraphicsDriverContentObserver.OnGraphicsDriverContentChangedListener, LifecycleObserver,
59         OnStart, OnStop {
60 
61     private final Context mContext;
62     private final ContentResolver mContentResolver;
63     private final String mPreferenceTitle;
64     private final String mPreferenceDefault;
65     private final String mPreferenceGameDriver;
66     private final String mPreferencePrereleaseDriver;
67     private final String mPreferenceSystem;
68     @VisibleForTesting
69     CharSequence[] mEntryList;
70     @VisibleForTesting
71     GraphicsDriverContentObserver mGraphicsDriverContentObserver;
72 
73     private final List<AppInfo> mAppInfos;
74     private final Set<String> mDevOptInApps;
75     private final Set<String> mDevPrereleaseOptInApps;
76     private final Set<String> mDevOptOutApps;
77 
78     private PreferenceGroup mPreferenceGroup;
79 
GraphicsDriverAppPreferenceController(Context context, String key)80     public GraphicsDriverAppPreferenceController(Context context, String key) {
81         super(context, key);
82 
83         mContext = context;
84         mContentResolver = context.getContentResolver();
85         mGraphicsDriverContentObserver =
86                 new GraphicsDriverContentObserver(new Handler(Looper.getMainLooper()), this);
87 
88         final Resources resources = context.getResources();
89         mPreferenceTitle = resources.getString(R.string.graphics_driver_app_preference_title);
90         mPreferenceDefault = resources.getString(R.string.graphics_driver_app_preference_default);
91         mPreferenceGameDriver =
92                 resources.getString(R.string.graphics_driver_app_preference_game_driver);
93         mPreferencePrereleaseDriver =
94                 resources.getString(R.string.graphics_driver_app_preference_prerelease_driver);
95         mPreferenceSystem = resources.getString(R.string.graphics_driver_app_preference_system);
96         mEntryList = GraphicsDriverEnableForAllAppsPreferenceController.constructEntryList(
97                 mContext, true);
98 
99         // TODO: Move this task to background if there's potential ANR/Jank.
100         // Update the UI when all the app infos are ready.
101         mAppInfos = getAppInfos(context);
102 
103         mDevOptInApps =
104                 getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS);
105         mDevPrereleaseOptInApps = getGlobalSettingsString(
106                 mContentResolver, Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS);
107         mDevOptOutApps =
108                 getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS);
109     }
110 
111     @Override
getAvailabilityStatus()112     public int getAvailabilityStatus() {
113         return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
114                 && (Settings.Global.getInt(mContentResolver,
115                 Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
116                 != GAME_DRIVER_OFF)
117                 ? AVAILABLE
118                 : CONDITIONALLY_UNAVAILABLE;
119     }
120 
121     @Override
displayPreference(PreferenceScreen screen)122     public void displayPreference(PreferenceScreen screen) {
123         super.displayPreference(screen);
124         mPreferenceGroup = screen.findPreference(getPreferenceKey());
125 
126         final Context context = mPreferenceGroup.getContext();
127         for (AppInfo appInfo : mAppInfos) {
128             mPreferenceGroup.addPreference(
129                     createListPreference(context, appInfo.info.packageName, appInfo.label));
130         }
131     }
132 
133     @Override
onStart()134     public void onStart() {
135         mGraphicsDriverContentObserver.register(mContentResolver);
136     }
137 
138     @Override
onStop()139     public void onStop() {
140         mGraphicsDriverContentObserver.unregister(mContentResolver);
141     }
142 
143     @Override
updateState(Preference preference)144     public void updateState(Preference preference) {
145         preference.setVisible(isAvailable());
146     }
147 
148     @Override
onPreferenceChange(Preference preference, Object newValue)149     public boolean onPreferenceChange(Preference preference, Object newValue) {
150         final ListPreference listPref = (ListPreference) preference;
151         final String value = newValue.toString();
152         final String packageName = preference.getKey();
153 
154         // When user choose a new preference, update both Sets for
155         // opt-in and opt-out apps. Then set the new summary text.
156         if (value.equals(mPreferenceSystem)) {
157             mDevOptInApps.remove(packageName);
158             mDevPrereleaseOptInApps.remove(packageName);
159             mDevOptOutApps.add(packageName);
160         } else if (value.equals(mPreferenceGameDriver)) {
161             mDevOptInApps.add(packageName);
162             mDevPrereleaseOptInApps.remove(packageName);
163             mDevOptOutApps.remove(packageName);
164         } else if (value.equals(mPreferencePrereleaseDriver)) {
165             mDevOptInApps.remove(packageName);
166             mDevPrereleaseOptInApps.add(packageName);
167             mDevOptOutApps.remove(packageName);
168         } else {
169             mDevOptInApps.remove(packageName);
170             mDevPrereleaseOptInApps.remove(packageName);
171             mDevOptOutApps.remove(packageName);
172         }
173         listPref.setValue(value);
174         listPref.setSummary(value);
175 
176         // Push the updated Sets for stable/prerelease opt-in and opt-out apps to
177         // corresponding Settings.Global.GAME_DRIVER(_PRERELEASE)?_OPT_(IN|OUT)_APPS
178         Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS,
179                 String.join(",", mDevOptInApps));
180         Settings.Global.putString(mContentResolver,
181                 Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS,
182                 String.join(",", mDevPrereleaseOptInApps));
183         Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
184                 String.join(",", mDevOptOutApps));
185 
186         return true;
187     }
188 
189     @Override
onGraphicsDriverContentChanged()190     public void onGraphicsDriverContentChanged() {
191         updateState(mPreferenceGroup);
192     }
193 
194     // AppInfo class to achieve loading the application label only once
195     class AppInfo {
AppInfo(PackageManager packageManager, ApplicationInfo applicationInfo)196         AppInfo(PackageManager packageManager, ApplicationInfo applicationInfo) {
197             info = applicationInfo;
198             label = packageManager.getApplicationLabel(applicationInfo).toString();
199         }
200 
201         public final ApplicationInfo info;
202         public final String label;
203     }
204 
205     // List of non-system packages that are installed for the current user.
getAppInfos(Context context)206     private List<AppInfo> getAppInfos(Context context) {
207         final PackageManager packageManager = context.getPackageManager();
208         final List<ApplicationInfo> applicationInfos =
209                 packageManager.getInstalledApplications(0 /* flags */);
210 
211         final List<AppInfo> appInfos = new ArrayList<>();
212         for (ApplicationInfo applicationInfo : applicationInfos) {
213             if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
214                 appInfos.add(new AppInfo(packageManager, applicationInfo));
215             }
216         }
217 
218         Collections.sort(appInfos, mAppInfoComparator);
219 
220         return appInfos;
221     }
222 
223     // Parse the raw comma separated package names into a String Set
getGlobalSettingsString(ContentResolver contentResolver, String name)224     private Set<String> getGlobalSettingsString(ContentResolver contentResolver, String name) {
225         final String settingsValue = Settings.Global.getString(contentResolver, name);
226         if (settingsValue == null) {
227             return new HashSet<>();
228         }
229 
230         final Set<String> valueSet = new HashSet<>(Arrays.asList(settingsValue.split(",")));
231         valueSet.remove("");
232 
233         return valueSet;
234     }
235 
236     private final Comparator<AppInfo> mAppInfoComparator = new Comparator<AppInfo>() {
237         public int compare(AppInfo a, AppInfo b) {
238             return Collator.getInstance().compare(a.label, b.label);
239         }
240     };
241 
242     @VisibleForTesting
createListPreference( Context context, String packageName, String appName)243     protected ListPreference createListPreference(
244             Context context, String packageName, String appName) {
245         final ListPreference listPreference = new ListPreference(context);
246 
247         listPreference.setKey(packageName);
248         listPreference.setTitle(appName);
249         listPreference.setDialogTitle(mPreferenceTitle);
250         listPreference.setEntries(mEntryList);
251         listPreference.setEntryValues(mEntryList);
252 
253         // Initialize preference default and summary with the opt in/out choices
254         // from Settings.Global.GAME_DRIVER(_PRERELEASE)?_OPT_(IN|OUT)_APPS
255         if (mDevOptOutApps.contains(packageName)) {
256             listPreference.setValue(mPreferenceSystem);
257             listPreference.setSummary(mPreferenceSystem);
258         } else if (mDevPrereleaseOptInApps.contains(packageName)) {
259             listPreference.setValue(mPreferencePrereleaseDriver);
260             listPreference.setSummary(mPreferencePrereleaseDriver);
261         } else if (mDevOptInApps.contains(packageName)) {
262             listPreference.setValue(mPreferenceGameDriver);
263             listPreference.setSummary(mPreferenceGameDriver);
264         } else {
265             listPreference.setValue(mPreferenceDefault);
266             listPreference.setSummary(mPreferenceDefault);
267         }
268 
269         listPreference.setOnPreferenceChangeListener(this);
270 
271         return listPreference;
272     }
273 }
274