1 /*
2  * Copyright (C) 2017 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.enterprise;
18 
19 import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
21 
22 import android.app.admin.DevicePolicyManager;
23 import android.content.Context;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.UserInfo;
27 import android.os.UserHandle;
28 
29 import androidx.preference.Preference;
30 import androidx.preference.PreferenceCategory;
31 import androidx.preference.PreferenceGroup;
32 import androidx.preference.PreferenceScreen;
33 
34 import com.android.settings.R;
35 import com.android.settings.SettingsPreferenceFragment;
36 import com.android.settings.applications.ApplicationFeatureProvider;
37 import com.android.settings.applications.EnterpriseDefaultApps;
38 import com.android.settings.applications.UserAppInfo;
39 import com.android.settings.core.PreferenceControllerMixin;
40 import com.android.settings.overlay.FeatureFactory;
41 import com.android.settings.users.UserFeatureProvider;
42 import com.android.settingslib.core.AbstractPreferenceController;
43 import com.android.settingslib.utils.StringUtil;
44 import com.android.settingslib.utils.ThreadUtils;
45 
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.EnumMap;
49 import java.util.List;
50 
51 
52 /**
53  * PreferenceController that builds a dynamic list of default apps set by device or profile owner.
54  */
55 public class EnterpriseSetDefaultAppsListPreferenceController extends
56         AbstractPreferenceController implements PreferenceControllerMixin {
57     private final PackageManager mPm;
58     private final SettingsPreferenceFragment mParent;
59     private final ApplicationFeatureProvider mApplicationFeatureProvider;
60     private final EnterprisePrivacyFeatureProvider mEnterprisePrivacyFeatureProvider;
61     private final UserFeatureProvider mUserFeatureProvider;
62 
63     private List<UserInfo> mUsers = Collections.emptyList();
64     private List<EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>>> mApps =
65             Collections.emptyList();
66 
EnterpriseSetDefaultAppsListPreferenceController(Context context, SettingsPreferenceFragment parent, PackageManager packageManager)67     public EnterpriseSetDefaultAppsListPreferenceController(Context context,
68             SettingsPreferenceFragment parent, PackageManager packageManager) {
69         super(context);
70         mPm = packageManager;
71         mParent = parent;
72         final FeatureFactory factory = FeatureFactory.getFeatureFactory();
73         mApplicationFeatureProvider = factory.getApplicationFeatureProvider();
74         mEnterprisePrivacyFeatureProvider = factory.getEnterprisePrivacyFeatureProvider();
75         mUserFeatureProvider = factory.getUserFeatureProvider();
76         buildAppList();
77     }
78 
79     /**
80      * Builds data for UI. Updates mUsers and mApps so that they contain non-empty list.
81      */
buildAppList()82     private void buildAppList() {
83         mUsers = new ArrayList<>();
84         mApps = new ArrayList<>();
85         for (UserHandle user : mUserFeatureProvider.getUserProfiles()) {
86             boolean hasDefaultsForUser = false;
87             EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> userMap = null;
88 
89             for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) {
90                 List<UserAppInfo> apps = mApplicationFeatureProvider.
91                         findPersistentPreferredActivities(user.getIdentifier(),
92                                 typeOfDefault.getIntents());
93                 if (apps.isEmpty()) {
94                     continue;
95                 }
96                 if (!hasDefaultsForUser) {
97                     hasDefaultsForUser = true;
98                     mUsers.add(apps.get(0).userInfo);
99                     userMap = new EnumMap<>(EnterpriseDefaultApps.class);
100                     mApps.add(userMap);
101                 }
102                 ArrayList<ApplicationInfo> applicationInfos = new ArrayList<>();
103                 for (UserAppInfo userAppInfo : apps) {
104                     applicationInfos.add(userAppInfo.appInfo);
105                 }
106                 userMap.put(typeOfDefault, applicationInfos);
107             }
108         }
109         ThreadUtils.postOnMainThread(() -> updateUi());
110     }
111 
112     @Override
isAvailable()113     public boolean isAvailable() {
114         return true;
115     }
116 
117     @Override
getPreferenceKey()118     public String getPreferenceKey() {
119         return null;
120     }
121 
updateUi()122     private void updateUi() {
123         final Context prefContext = mParent.getPreferenceManager().getContext();
124         final PreferenceScreen screen = mParent.getPreferenceScreen();
125         if (screen == null) {
126             return;
127         }
128         if (!mEnterprisePrivacyFeatureProvider.isInCompMode() && mUsers.size() == 1) {
129             createPreferences(prefContext, screen, mApps.get(0));
130         } else {
131             DevicePolicyManager devicePolicyManager =
132                     mContext.getSystemService(DevicePolicyManager.class);
133             for (int i = 0; i < mUsers.size(); i++) {
134                 final UserInfo userInfo = mUsers.get(i);
135                 final PreferenceCategory category = new PreferenceCategory(prefContext);
136                 screen.addPreference(category);
137                 if (userInfo.isManagedProfile()) {
138                     category.setTitle(devicePolicyManager.getResources().getString(
139                             WORK_CATEGORY_HEADER,
140                             () -> mContext.getString(
141                                     com.android.settingslib.R.string.category_work)));
142                 } else {
143                     category.setTitle(devicePolicyManager.getResources().getString(
144                             PERSONAL_CATEGORY_HEADER,
145                             () -> mContext.getString(
146                                     com.android.settingslib.R.string.category_personal)));
147                 }
148                 category.setOrder(i);
149                 createPreferences(prefContext, category, mApps.get(i));
150             }
151         }
152     }
153 
createPreferences(Context prefContext, PreferenceGroup group, EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> apps)154     private void createPreferences(Context prefContext, PreferenceGroup group,
155             EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> apps) {
156         if (group == null) {
157             return;
158         }
159         for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) {
160             final List<ApplicationInfo> appsForCategory = apps.get(typeOfDefault);
161             if (appsForCategory == null || appsForCategory.isEmpty()) {
162                 continue;
163             }
164             final Preference preference = new Preference(prefContext);
165             preference.setTitle(getTitle(prefContext, typeOfDefault, appsForCategory.size()));
166             preference.setSummary(buildSummaryString(prefContext, appsForCategory));
167             preference.setOrder(typeOfDefault.ordinal());
168             preference.setSelectable(false);
169             group.addPreference(preference);
170         }
171     }
172 
buildSummaryString(Context context, List<ApplicationInfo> apps)173     private CharSequence buildSummaryString(Context context, List<ApplicationInfo> apps) {
174         final CharSequence[] appNames = new String[apps.size()];
175         for (int i = 0; i < apps.size(); i++) {
176             appNames[i] = apps.get(i).loadLabel(mPm);
177         }
178         if (apps.size() == 1) {
179             return appNames[0];
180         } else if (apps.size() == 2) {
181             return context.getString(R.string.app_names_concatenation_template_2, appNames[0],
182                     appNames[1]);
183         } else {
184             return context.getString(R.string.app_names_concatenation_template_3, appNames[0],
185                     appNames[1], appNames[2]);
186         }
187     }
188 
getTitle(Context context, EnterpriseDefaultApps typeOfDefault, int appCount)189     private String getTitle(Context context, EnterpriseDefaultApps typeOfDefault, int appCount) {
190         switch (typeOfDefault) {
191             case BROWSER:
192                 return context.getString(R.string.default_browser_title);
193             case CALENDAR:
194                 return context.getString(R.string.default_calendar_app_title);
195             case CONTACTS:
196                 return context.getString(R.string.default_contacts_app_title);
197             case PHONE:
198                 return StringUtil.getIcuPluralsString(context, appCount,
199                         R.string.default_phone_app_title);
200             case MAP:
201                 return context.getString(R.string.default_map_app_title);
202             case EMAIL:
203                 return StringUtil.getIcuPluralsString(context, appCount,
204                         R.string.default_email_app_title);
205             case CAMERA:
206                 return StringUtil.getIcuPluralsString(context, appCount,
207                         R.string.default_camera_app_title);
208             default:
209                 throw new IllegalStateException("Unknown type of default " + typeOfDefault);
210         }
211     }
212 
213 }
214