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.car.settings.enterprise; 17 18 import android.annotation.Nullable; 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.content.pm.ApplicationInfo; 22 import android.os.UserHandle; 23 24 import androidx.preference.PreferenceGroup; 25 26 import com.android.car.settings.R; 27 import com.android.car.settings.common.FragmentController; 28 import com.android.car.settingslib.applications.ApplicationFeatureProvider; 29 import com.android.car.settingslib.applications.UserAppInfo; 30 import com.android.car.settingslib.enterprise.EnterpriseDefaultApps; 31 import com.android.car.ui.preference.CarUiPreference; 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.util.ArrayList; 35 import java.util.EnumMap; 36 import java.util.List; 37 38 /** 39 * Controller to show the list of default apps were set by the device owner. 40 */ 41 public final class EnterpriseSetDefaultAppsListPreferenceController 42 extends BaseEnterprisePrivacyPreferenceController<PreferenceGroup> { 43 44 @Nullable 45 private EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> mAllApps; 46 EnterpriseSetDefaultAppsListPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)47 public EnterpriseSetDefaultAppsListPreferenceController(Context context, String preferenceKey, 48 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 49 this(context, preferenceKey, fragmentController, uxRestrictions, 50 /* applicationFeatureProvider= */ null); 51 } 52 53 @VisibleForTesting EnterpriseSetDefaultAppsListPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, @Nullable ApplicationFeatureProvider applicationFeatureProvider)54 EnterpriseSetDefaultAppsListPreferenceController(Context context, String preferenceKey, 55 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 56 @Nullable ApplicationFeatureProvider applicationFeatureProvider) { 57 super(context, preferenceKey, fragmentController, uxRestrictions, 58 /* enterprisePrivacyFeatureProvider= */ null, applicationFeatureProvider); 59 } 60 61 @Override getPreferenceType()62 protected Class<PreferenceGroup> getPreferenceType() { 63 return PreferenceGroup.class; 64 } 65 66 @Override getDefaultAvailabilityStatus()67 protected int getDefaultAvailabilityStatus() { 68 if (mAllApps == null) { 69 mAllApps = listEnterpriseSetDefaultApps(); 70 mLogger.d("All apps: " + mAllApps); 71 } 72 73 return mAllApps == null || mAllApps.isEmpty() ? DISABLED_FOR_PROFILE : AVAILABLE; 74 } 75 76 @Override updateState(PreferenceGroup preferenceGroup)77 protected void updateState(PreferenceGroup preferenceGroup) { 78 if (mAllApps == null) { 79 // Should never happen, but better log than crash... 80 mLogger.wtf("updateState() called when mAllApps is null"); 81 return; 82 } 83 mLogger.d("Updating state with " + mAllApps.size() + " types of apps"); 84 85 createPreferences(getContext(), preferenceGroup, mAllApps); 86 }; 87 88 // NOTE: methods below were copied from phone, mostly "as-is" 89 90 @Nullable listEnterpriseSetDefaultApps()91 private EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> listEnterpriseSetDefaultApps() { 92 // TODO(b/1703325190): to support work profiles, it should use and outer lopp: 93 // for (UserHandle user : mUserFeatureProvider.getUserProfiles()) { 94 UserHandle user = getContext().getUser(); 95 boolean hasDefaultsForUser = false; 96 EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> userMap = null; 97 98 for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) { 99 List<UserAppInfo> apps = mApplicationFeatureProvider 100 .findPersistentPreferredActivities(user.getIdentifier(), 101 typeOfDefault.getIntents()); 102 if (apps.isEmpty()) { 103 mLogger.v("no app of type " + typeOfDefault + " for user " + user); 104 continue; 105 } 106 if (!hasDefaultsForUser) { 107 hasDefaultsForUser = true; 108 userMap = new EnumMap<>(EnterpriseDefaultApps.class); 109 } 110 ArrayList<ApplicationInfo> applicationInfos = new ArrayList<>(); 111 for (UserAppInfo userAppInfo : apps) { 112 mLogger.d("adding app of type " + typeOfDefault + ":" + userAppInfo); 113 applicationInfos.add(userAppInfo.appInfo); 114 } 115 userMap.put(typeOfDefault, applicationInfos); 116 } 117 return userMap; 118 } 119 createPreferences(Context prefContext, PreferenceGroup group, EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> apps)120 private void createPreferences(Context prefContext, PreferenceGroup group, 121 EnumMap<EnterpriseDefaultApps, List<ApplicationInfo>> apps) { 122 group.removeAll(); 123 for (EnterpriseDefaultApps typeOfDefault : EnterpriseDefaultApps.values()) { 124 List<ApplicationInfo> appsForCategory = apps.get(typeOfDefault); 125 if (appsForCategory == null || appsForCategory.isEmpty()) { 126 mLogger.d("No app for type " + typeOfDefault); 127 continue; 128 } 129 CarUiPreference preference = new CarUiPreference(prefContext); 130 preference.setTitle(getTitle(prefContext, typeOfDefault, appsForCategory.size())); 131 preference.setSummary(buildSummaryString(prefContext, appsForCategory)); 132 preference.setOrder(typeOfDefault.ordinal()); 133 preference.setSelectable(false); 134 group.addPreference(preference); 135 } 136 } 137 buildSummaryString(Context context, List<ApplicationInfo> apps)138 private CharSequence buildSummaryString(Context context, List<ApplicationInfo> apps) { 139 CharSequence[] appNames = new String[apps.size()]; 140 for (int i = 0; i < apps.size(); i++) { 141 appNames[i] = apps.get(i).loadLabel(mPm); 142 } 143 switch (apps.size()) { 144 case 1: 145 return appNames[0]; 146 case 2: 147 return context.getString(R.string.app_names_concatenation_template_2, appNames[0], 148 appNames[1]); 149 default: 150 return context.getString(R.string.app_names_concatenation_template_3, appNames[0], 151 appNames[1], appNames[2]); 152 } 153 } 154 getTitle(Context context, EnterpriseDefaultApps typeOfDefault, int appCount)155 private CharSequence getTitle(Context context, EnterpriseDefaultApps typeOfDefault, 156 int appCount) { 157 switch (typeOfDefault) { 158 case BROWSER: 159 return context.getString(R.string.default_browser_title); 160 case CALENDAR: 161 return context.getString(R.string.default_calendar_app_title); 162 case CONTACTS: 163 return context.getString(R.string.default_contacts_app_title); 164 case PHONE: 165 return context.getResources() 166 .getQuantityString(R.plurals.default_phone_app_title, appCount); 167 case MAP: 168 return context.getString(R.string.default_map_app_title); 169 case EMAIL: 170 return context.getResources() 171 .getQuantityString(R.plurals.default_email_app_title, appCount); 172 case CAMERA: 173 return context.getResources() 174 .getQuantityString(R.plurals.default_camera_app_title, appCount); 175 default: 176 throw new IllegalStateException("Unknown type of default " + typeOfDefault); 177 } 178 } 179 } 180