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.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.PackageInfo; 23 import android.graphics.drawable.Drawable; 24 import android.os.Bundle; 25 import android.os.UserHandle; 26 import android.widget.Toast; 27 28 import androidx.annotation.NonNull; 29 import androidx.fragment.app.Fragment; 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceCategory; 32 import androidx.preference.PreferenceGroup; 33 import androidx.preference.PreferenceScreen; 34 35 import com.android.packageinstaller.auto.AutoSettingsFrameFragment; 36 import com.android.packageinstaller.permission.model.AppPermissionGroup; 37 import com.android.packageinstaller.permission.model.AppPermissions; 38 import com.android.packageinstaller.permission.ui.AppPermissionActivity; 39 import com.android.packageinstaller.permission.utils.Utils; 40 import com.android.permissioncontroller.R; 41 42 import java.text.Collator; 43 import java.util.ArrayList; 44 45 /** Screen to show the permissions for a specific application. */ 46 public class AutoAppPermissionsFragment extends AutoSettingsFrameFragment { 47 48 private static final String KEY_ALLOWED_PERMISSIONS_GROUP = "allowed_permissions_group"; 49 private static final String KEY_DENIED_PERMISSIONS_GROUP = "denied_permissions_group"; 50 51 private AppPermissions mAppPermissions; 52 private PreferenceScreen mExtraScreen; 53 54 private Collator mCollator; 55 56 /** 57 * @return A new fragment 58 */ newInstance(@onNull String packageName, @NonNull UserHandle userHandle)59 public static AutoAppPermissionsFragment newInstance(@NonNull String packageName, 60 @NonNull UserHandle userHandle) { 61 return setPackageNameAndUserHandle(new AutoAppPermissionsFragment(), packageName, 62 userHandle); 63 } 64 setPackageNameAndUserHandle(@onNull T fragment, @NonNull String packageName, @NonNull UserHandle userHandle)65 private static <T extends Fragment> T setPackageNameAndUserHandle(@NonNull T fragment, 66 @NonNull String packageName, @NonNull UserHandle userHandle) { 67 Bundle arguments = new Bundle(); 68 arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); 69 arguments.putParcelable(Intent.EXTRA_USER, userHandle); 70 fragment.setArguments(arguments); 71 return fragment; 72 } 73 74 @Override onCreate(Bundle savedInstanceState)75 public void onCreate(Bundle savedInstanceState) { 76 super.onCreate(savedInstanceState); 77 setLoading(true); 78 79 String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); 80 UserHandle userHandle = getArguments().getParcelable(Intent.EXTRA_USER); 81 Activity activity = requireActivity(); 82 PackageInfo packageInfo = AutoPermissionsUtils.getPackageInfo(activity, packageName, 83 userHandle); 84 if (packageInfo == null) { 85 Toast.makeText(getContext(), R.string.app_not_found_dlg_title, 86 Toast.LENGTH_LONG).show(); 87 activity.finish(); 88 return; 89 } 90 91 setHeaderLabel(getContext().getString(R.string.app_permissions)); 92 setAction(getContext().getString(R.string.all_permissions), v -> showAllPermissions()); 93 94 mAppPermissions = new AppPermissions(activity, packageInfo, /* sortGroups= */ true, 95 () -> getActivity().finish()); 96 97 mCollator = Collator.getInstance( 98 getContext().getResources().getConfiguration().getLocales().get(0)); 99 } 100 101 @Override onCreatePreferences(Bundle bundle, String s)102 public void onCreatePreferences(Bundle bundle, String s) { 103 setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext())); 104 } 105 106 @Override onStart()107 public void onStart() { 108 super.onStart(); 109 mAppPermissions.refresh(); 110 bindUi(mAppPermissions.getPackageInfo()); 111 updatePreferences(); 112 } 113 114 @Override onStop()115 public void onStop() { 116 super.onStop(); 117 getPreferenceScreen().removeAll(); 118 } 119 showAllPermissions()120 private void showAllPermissions() { 121 Fragment frag = AutoAllAppPermissionsFragment.newInstance( 122 getArguments().getString(Intent.EXTRA_PACKAGE_NAME), 123 getArguments().getParcelable(Intent.EXTRA_USER)); 124 getFragmentManager().beginTransaction() 125 .replace(android.R.id.content, frag) 126 .addToBackStack("AllPerms") 127 .commit(); 128 } 129 bindUi(PackageInfo packageInfo)130 protected void bindUi(PackageInfo packageInfo) { 131 getPreferenceScreen().addPreference( 132 AutoPermissionsUtils.createHeaderPreference(getContext(), 133 packageInfo.applicationInfo)); 134 135 PreferenceGroup allowed = new PreferenceCategory(getContext()); 136 allowed.setKey(KEY_ALLOWED_PERMISSIONS_GROUP); 137 allowed.setTitle(R.string.allowed_header); 138 getPreferenceScreen().addPreference(allowed); 139 140 PreferenceGroup denied = new PreferenceCategory(getContext()); 141 denied.setKey(KEY_DENIED_PERMISSIONS_GROUP); 142 denied.setTitle(R.string.denied_header); 143 getPreferenceScreen().addPreference(denied); 144 } 145 updatePreferences()146 private void updatePreferences() { 147 Context context = getPreferenceManager().getContext(); 148 if (context == null) { 149 return; 150 } 151 152 PreferenceCategory allowed = findPreference(KEY_ALLOWED_PERMISSIONS_GROUP); 153 PreferenceCategory denied = findPreference(KEY_DENIED_PERMISSIONS_GROUP); 154 155 allowed.removeAll(); 156 denied.removeAll(); 157 158 if (mExtraScreen != null) { 159 mExtraScreen.removeAll(); 160 mExtraScreen.addPreference(AutoPermissionsUtils.createHeaderPreference(getContext(), 161 mAppPermissions.getPackageInfo().applicationInfo)); 162 } 163 164 Preference extraPerms = new Preference(context); 165 extraPerms.setIcon(R.drawable.ic_toc); 166 extraPerms.setTitle(R.string.additional_permissions); 167 boolean extraPermsAreAllowed = false; 168 169 ArrayList<AppPermissionGroup> groups = new ArrayList<>( 170 mAppPermissions.getPermissionGroups()); 171 groups.sort((x, y) -> mCollator.compare(x.getLabel(), y.getLabel())); 172 allowed.setOrderingAsAdded(true); 173 denied.setOrderingAsAdded(true); 174 175 for (int i = 0; i < groups.size(); i++) { 176 AppPermissionGroup group = groups.get(i); 177 if (!Utils.shouldShowPermission(getContext(), group)) { 178 continue; 179 } 180 181 boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); 182 183 Preference preference = createPermissionPreference(getContext(), group); 184 if (isPlatform) { 185 PreferenceCategory category = 186 group.areRuntimePermissionsGranted() ? allowed : denied; 187 category.addPreference(preference); 188 } else { 189 if (mExtraScreen == null) { 190 mExtraScreen = getPreferenceManager().createPreferenceScreen(context); 191 mExtraScreen.addPreference( 192 AutoPermissionsUtils.createHeaderPreference(getContext(), 193 mAppPermissions.getPackageInfo().applicationInfo)); 194 } 195 mExtraScreen.addPreference(preference); 196 if (group.areRuntimePermissionsGranted()) { 197 extraPermsAreAllowed = true; 198 } 199 } 200 } 201 202 if (mExtraScreen != null) { 203 extraPerms.setOnPreferenceClickListener(preference -> { 204 AutoAppPermissionsFragment.AdditionalPermissionsFragment 205 frag = new AutoAppPermissionsFragment.AdditionalPermissionsFragment(); 206 setPackageNameAndUserHandle(frag, 207 getArguments().getString(Intent.EXTRA_PACKAGE_NAME), 208 getArguments().getParcelable(Intent.EXTRA_USER)); 209 frag.setTargetFragment(AutoAppPermissionsFragment.this, 0); 210 getFragmentManager().beginTransaction() 211 .replace(android.R.id.content, frag) 212 .addToBackStack(null) 213 .commit(); 214 return true; 215 }); 216 // Delete 1 to account for app header preference. 217 int count = mExtraScreen.getPreferenceCount() - 1; 218 extraPerms.setSummary(getResources().getQuantityString( 219 R.plurals.additional_permissions_more, count, 220 count)); 221 PreferenceCategory category = extraPermsAreAllowed ? allowed : denied; 222 category.addPreference(extraPerms); 223 } 224 225 if (allowed.getPreferenceCount() == 0) { 226 Preference empty = new Preference(context); 227 empty.setTitle(getString(R.string.no_permissions_allowed)); 228 empty.setSelectable(false); 229 allowed.addPreference(empty); 230 } 231 if (denied.getPreferenceCount() == 0) { 232 Preference empty = new Preference(context); 233 empty.setTitle(getString(R.string.no_permissions_denied)); 234 empty.setSelectable(false); 235 denied.addPreference(empty); 236 } 237 238 setLoading(false); 239 } 240 createPermissionPreference(Context context, AppPermissionGroup group)241 private Preference createPermissionPreference(Context context, AppPermissionGroup group) { 242 Preference preference = new Preference(context); 243 Drawable icon = Utils.loadDrawable(context.getPackageManager(), 244 group.getIconPkg(), group.getIconResId()); 245 preference.setKey(group.getName()); 246 preference.setTitle(group.getFullLabel()); 247 preference.setIcon(Utils.applyTint(context, icon, android.R.attr.colorControlNormal)); 248 preference.setOnPreferenceClickListener(pref -> { 249 Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION); 250 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, group.getApp().packageName); 251 intent.putExtra(Intent.EXTRA_PERMISSION_NAME, group.getPermissions().get(0).getName()); 252 intent.putExtra(Intent.EXTRA_USER, group.getUser()); 253 intent.putExtra(AppPermissionActivity.EXTRA_CALLER_NAME, 254 AutoAppPermissionsFragment.class.getName()); 255 context.startActivity(intent); 256 return true; 257 }); 258 return preference; 259 } 260 getGroupSummary(AppPermissionGroup group)261 private String getGroupSummary(AppPermissionGroup group) { 262 if (group.hasPermissionWithBackgroundMode() && group.areRuntimePermissionsGranted()) { 263 AppPermissionGroup backgroundGroup = group.getBackgroundPermissions(); 264 if (backgroundGroup == null || !backgroundGroup.areRuntimePermissionsGranted()) { 265 return getContext().getString(R.string.permission_subtitle_only_in_foreground); 266 } 267 } 268 return null; 269 } 270 271 /** 272 * Class that shows additional permissions. 273 */ 274 public static class AdditionalPermissionsFragment extends AutoSettingsFrameFragment { 275 AutoAppPermissionsFragment mOuterFragment; 276 277 @Override onCreate(Bundle savedInstanceState)278 public void onCreate(Bundle savedInstanceState) { 279 // Set this before calling super.onCreate as it is needed in onCreatePreferences 280 // (which is called from super.onCreate). 281 mOuterFragment = (AutoAppPermissionsFragment) getTargetFragment(); 282 super.onCreate(savedInstanceState); 283 setHeaderLabel(mOuterFragment.getHeaderLabel()); 284 } 285 286 @Override onCreatePreferences(Bundle bundle, String s)287 public void onCreatePreferences(Bundle bundle, String s) { 288 setPreferenceScreen(mOuterFragment.mExtraScreen); 289 } 290 } 291 } 292 293