1 /* 2 * Copyright (C) 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.packageinstaller.permission.ui.auto; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.graphics.drawable.Drawable; 22 import android.os.Bundle; 23 import android.util.ArrayMap; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 import androidx.fragment.app.Fragment; 28 import androidx.preference.Preference; 29 import androidx.preference.PreferenceCategory; 30 import androidx.preference.PreferenceGroup; 31 32 import com.android.packageinstaller.auto.AutoSettingsFrameFragment; 33 import com.android.packageinstaller.permission.model.AppPermissionGroup; 34 import com.android.packageinstaller.permission.model.PermissionApps; 35 import com.android.packageinstaller.permission.model.PermissionApps.Callback; 36 import com.android.packageinstaller.permission.ui.handheld.PermissionAppsFragment; 37 import com.android.packageinstaller.permission.ui.handheld.PermissionControlPreference; 38 import com.android.packageinstaller.permission.utils.Utils; 39 import com.android.permissioncontroller.R; 40 41 import java.text.Collator; 42 import java.util.ArrayList; 43 import java.util.Map; 44 45 /** Shows the list of applications which have (or do not have) the given permission. */ 46 public class AutoPermissionAppsFragment extends AutoSettingsFrameFragment implements Callback { 47 48 private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem"; 49 private static final String KEY_ALLOWED_PERMISSIONS_GROUP = "allowed_permissions_group"; 50 private static final String KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP = 51 "allowed_foreground_permissions_group"; 52 private static final String KEY_DENIED_PERMISSIONS_GROUP = "denied_permissions_group"; 53 54 private static final String SHOW_SYSTEM_KEY = AutoPermissionAppsFragment.class.getName() 55 + KEY_SHOW_SYSTEM_PREFS; 56 57 /** Creates a new instance of {@link AutoPermissionAppsFragment} for the given permission. */ newInstance(String permissionName)58 public static AutoPermissionAppsFragment newInstance(String permissionName) { 59 return setPermissionName(new AutoPermissionAppsFragment(), permissionName); 60 } 61 setPermissionName(T fragment, String permissionName)62 private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) { 63 Bundle arguments = new Bundle(); 64 arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName); 65 fragment.setArguments(arguments); 66 return fragment; 67 } 68 69 private PermissionApps mPermissionApps; 70 71 private boolean mShowSystem; 72 private boolean mHasSystemApps; 73 74 private Collator mCollator; 75 76 @Override onCreate(@ullable Bundle savedInstanceState)77 public void onCreate(@Nullable Bundle savedInstanceState) { 78 super.onCreate(savedInstanceState); 79 80 if (savedInstanceState != null) { 81 mShowSystem = savedInstanceState.getBoolean(SHOW_SYSTEM_KEY); 82 } 83 84 setLoading(true); 85 86 String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME); 87 mPermissionApps = new PermissionApps(getActivity(), groupName, /* callback= */ this); 88 mPermissionApps.refresh(/* getUiInfo= */ true); 89 90 mCollator = Collator.getInstance( 91 getContext().getResources().getConfiguration().getLocales().get(0)); 92 93 setShowSystemAppsToggle(); 94 bindUi(mPermissionApps, groupName); 95 } 96 97 @Override onCreatePreferences(Bundle bundle, String s)98 public void onCreatePreferences(Bundle bundle, String s) { 99 setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext())); 100 } 101 102 @Override onSaveInstanceState(Bundle outState)103 public void onSaveInstanceState(Bundle outState) { 104 super.onSaveInstanceState(outState); 105 106 outState.putBoolean(SHOW_SYSTEM_KEY, mShowSystem); 107 } 108 109 @Override onStart()110 public void onStart() { 111 super.onStart(); 112 mPermissionApps.refresh(/* getUiInfo= */ true); 113 } 114 setShowSystemAppsToggle()115 private void setShowSystemAppsToggle() { 116 if (!mHasSystemApps) { 117 setAction(/* label= */ null, /* onClickListener= */ null); 118 return; 119 } 120 121 // Show the opposite label from the current state. 122 String label; 123 if (mShowSystem) { 124 label = getString(R.string.menu_hide_system); 125 } else { 126 label = getString(R.string.menu_show_system); 127 } 128 129 setAction(label, v -> { 130 mShowSystem = !mShowSystem; 131 if (mPermissionApps.getApps() != null) { 132 onPermissionsLoaded(mPermissionApps); 133 } 134 setShowSystemAppsToggle(); 135 }); 136 } 137 bindUi(PermissionApps permissionApps, @NonNull String groupName)138 private void bindUi(PermissionApps permissionApps, @NonNull String groupName) { 139 CharSequence label = permissionApps.getFullLabel(); 140 setHeaderLabel(label); 141 142 Drawable icon = permissionApps.getIcon(); 143 Preference header = new Preference(getContext()); 144 header.setTitle(label); 145 header.setIcon(icon); 146 header.setSummary(Utils.getPermissionGroupDescriptionString(getContext(), groupName, 147 permissionApps.getDescription())); 148 getPreferenceScreen().addPreference(header); 149 150 PreferenceGroup allowed = new PreferenceCategory(getContext()); 151 allowed.setKey(KEY_ALLOWED_PERMISSIONS_GROUP); 152 allowed.setTitle(R.string.allowed_header); 153 allowed.setVisible(false); 154 getPreferenceScreen().addPreference(allowed); 155 156 PreferenceGroup foreground = new PreferenceCategory(getContext()); 157 foreground.setKey(KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP); 158 foreground.setTitle(R.string.allowed_foreground_header); 159 foreground.setVisible(false); 160 getPreferenceScreen().addPreference(foreground); 161 162 PreferenceGroup denied = new PreferenceCategory(getContext()); 163 denied.setKey(KEY_DENIED_PERMISSIONS_GROUP); 164 denied.setTitle(R.string.denied_header); 165 denied.setVisible(false); 166 getPreferenceScreen().addPreference(denied); 167 } 168 169 @Override onPermissionsLoaded(PermissionApps permissionApps)170 public void onPermissionsLoaded(PermissionApps permissionApps) { 171 Context context = getPreferenceManager().getContext(); 172 173 if (context == null || getActivity() == null) { 174 return; 175 } 176 177 PreferenceCategory allowed = findPreference(KEY_ALLOWED_PERMISSIONS_GROUP); 178 PreferenceCategory allowedForeground = findPreference( 179 KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP); 180 PreferenceCategory denied = findPreference(KEY_DENIED_PERMISSIONS_GROUP); 181 182 allowed.setOrderingAsAdded(true); 183 allowedForeground.setOrderingAsAdded(true); 184 denied.setOrderingAsAdded(true); 185 186 Map<String, Preference> existingPrefs = new ArrayMap<>(); 187 int numPreferences = allowed.getPreferenceCount(); 188 for (int i = 0; i < numPreferences; i++) { 189 Preference preference = allowed.getPreference(i); 190 existingPrefs.put(preference.getKey(), preference); 191 } 192 allowed.removeAll(); 193 numPreferences = allowedForeground.getPreferenceCount(); 194 for (int i = 0; i < numPreferences; i++) { 195 Preference preference = allowedForeground.getPreference(i); 196 existingPrefs.put(preference.getKey(), preference); 197 } 198 allowedForeground.removeAll(); 199 numPreferences = denied.getPreferenceCount(); 200 for (int i = 0; i < numPreferences; i++) { 201 Preference preference = denied.getPreference(i); 202 existingPrefs.put(preference.getKey(), preference); 203 } 204 denied.removeAll(); 205 206 mHasSystemApps = false; 207 boolean hasPermissionWithBackgroundMode = false; 208 209 ArrayList<PermissionApps.PermissionApp> sortedApps = new ArrayList<>( 210 permissionApps.getApps()); 211 sortedApps.sort((x, y) -> { 212 int result = mCollator.compare(x.getLabel(), y.getLabel()); 213 if (result == 0) { 214 result = x.getUid() - y.getUid(); 215 } 216 return result; 217 }); 218 219 for (int i = 0; i < sortedApps.size(); i++) { 220 PermissionApps.PermissionApp app = sortedApps.get(i); 221 AppPermissionGroup group = app.getPermissionGroup(); 222 223 hasPermissionWithBackgroundMode = 224 hasPermissionWithBackgroundMode || group.hasPermissionWithBackgroundMode(); 225 226 if (!Utils.shouldShowPermission(getContext(), group)) { 227 continue; 228 } 229 230 if (!app.getAppInfo().enabled) { 231 continue; 232 } 233 234 String key = app.getKey(); 235 Preference existingPref = existingPrefs.get(key); 236 if (existingPref != null) { 237 // Without this, existing preferences remember their old order. 238 existingPref.setOrder(Preference.DEFAULT_ORDER); 239 } 240 241 boolean isSystemApp = !Utils.isGroupOrBgGroupUserSensitive(group); 242 243 if (isSystemApp) { 244 mHasSystemApps = true; 245 } 246 247 if (isSystemApp && !mShowSystem) { 248 continue; 249 } 250 251 PreferenceCategory category; 252 if (group.areRuntimePermissionsGranted()) { 253 if (!group.hasPermissionWithBackgroundMode() 254 || (group.getBackgroundPermissions() != null 255 && group.getBackgroundPermissions().areRuntimePermissionsGranted())) { 256 category = allowed; 257 } else { 258 category = allowedForeground; 259 } 260 } else { 261 category = denied; 262 } 263 264 if (existingPref != null) { 265 category.addPreference(existingPref); 266 continue; 267 } 268 269 PermissionControlPreference pref = new PermissionControlPreference(context, group, 270 PermissionAppsFragment.class.getName()); 271 pref.setKey(key); 272 pref.setIcon(app.getIcon()); 273 pref.setTitle(Utils.getFullAppLabel(app.getAppInfo(), context)); 274 pref.setEllipsizeEnd(); 275 pref.useSmallerIcon(); 276 category.addPreference(pref); 277 } 278 279 if (hasPermissionWithBackgroundMode) { 280 allowed.setTitle(R.string.allowed_always_header); 281 } 282 283 if (allowed.getPreferenceCount() == 0) { 284 Preference empty = new Preference(context); 285 empty.setTitle(R.string.no_apps_allowed); 286 empty.setSelectable(false); 287 allowed.addPreference(empty); 288 } 289 allowed.setVisible(true); 290 291 allowedForeground.setVisible(allowedForeground.getPreferenceCount() > 0); 292 293 if (denied.getPreferenceCount() == 0) { 294 Preference empty = new Preference(context); 295 empty.setTitle(R.string.no_apps_denied); 296 empty.setSelectable(false); 297 denied.addPreference(empty); 298 } 299 denied.setVisible(true); 300 301 setShowSystemAppsToggle(); 302 setLoading(false); 303 } 304 } 305