AppPermissionsFragmentWear.java revision 5d9393b56c15883ede32d60309cbaed6f686f6a4
1/* 2* Copyright (C) 2015 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 17package com.android.packageinstaller.permission.ui.wear; 18 19import android.Manifest; 20import android.app.Activity; 21import android.app.Fragment; 22import android.content.Intent; 23import android.content.pm.PackageInfo; 24import android.content.pm.PackageManager; 25import android.content.pm.PermissionInfo; 26import android.os.Bundle; 27import android.os.UserHandle; 28import android.preference.Preference; 29import android.preference.PreferenceFragment; 30import android.preference.PreferenceScreen; 31import android.preference.SwitchPreference; 32import android.support.wearable.view.WearableDialogHelper; 33import android.util.Log; 34import android.view.LayoutInflater; 35import android.view.View; 36import android.view.ViewGroup; 37import android.widget.Toast; 38 39import com.android.packageinstaller.R; 40import com.android.packageinstaller.permission.model.AppPermissionGroup; 41import com.android.packageinstaller.permission.model.AppPermissions; 42import com.android.packageinstaller.permission.model.Permission; 43import com.android.packageinstaller.permission.utils.LocationUtils; 44import com.android.packageinstaller.permission.utils.SafetyNetLogger; 45import com.android.packageinstaller.permission.utils.Utils; 46import com.android.settingslib.RestrictedLockUtils; 47import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 48 49import java.util.ArrayList; 50import java.util.List; 51 52public final class AppPermissionsFragmentWear extends PreferenceFragment { 53 private static final String LOG_TAG = "AppPermFragWear"; 54 55 private static final String KEY_NO_PERMISSIONS = "no_permissions"; 56 57 public static AppPermissionsFragmentWear newInstance(String packageName) { 58 return setPackageName(new AppPermissionsFragmentWear(), packageName); 59 } 60 61 private static <T extends Fragment> T setPackageName(T fragment, String packageName) { 62 Bundle arguments = new Bundle(); 63 arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); 64 fragment.setArguments(arguments); 65 return fragment; 66 } 67 68 private PackageManager mPackageManager; 69 private List<AppPermissionGroup> mToggledGroups; 70 private AppPermissions mAppPermissions; 71 72 private boolean mHasConfirmedRevoke; 73 74 /** 75 * Provides click behavior for disabled preferences. 76 * We can't use {@link PreferenceFragment#onPreferenceTreeClick}, as the base 77 * {@link SwitchPreference} doesn't delegate to that method if the preference is disabled. 78 */ 79 private static class PermissionSwitchPreference extends SwitchPreference { 80 81 private final Activity mActivity; 82 83 public PermissionSwitchPreference(Activity activity) { 84 super(activity); 85 this.mActivity = activity; 86 } 87 88 @Override 89 public void performClick(PreferenceScreen preferenceScreen) { 90 super.performClick(preferenceScreen); 91 if (!isEnabled()) { 92 // If setting the permission is disabled, it must have been locked 93 // by the device or profile owner. So get that info and pass it to 94 // the support details dialog. 95 EnforcedAdmin deviceOrProfileOwner = RestrictedLockUtils.getProfileOrDeviceOwner( 96 mActivity, UserHandle.myUserId()); 97 RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 98 mActivity, deviceOrProfileOwner); 99 } 100 } 101 } 102 103 @Override 104 public void onCreate(Bundle savedInstanceState) { 105 super.onCreate(savedInstanceState); 106 107 String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); 108 Activity activity = getActivity(); 109 mPackageManager = activity.getPackageManager(); 110 111 PackageInfo packageInfo; 112 113 try { 114 packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); 115 } catch (PackageManager.NameNotFoundException e) { 116 Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); 117 packageInfo = null; 118 } 119 120 if (packageInfo == null) { 121 Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); 122 activity.finish(); 123 return; 124 } 125 126 mAppPermissions = new AppPermissions( 127 activity, packageInfo, null, true, () -> getActivity().finish()); 128 129 addPreferencesFromResource(R.xml.watch_permissions); 130 initializePermissionGroupList(); 131 } 132 133 @Override 134 public void onResume() { 135 super.onResume(); 136 mAppPermissions.refresh(); 137 138 // Also refresh the UI 139 for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { 140 if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { 141 for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { 142 setPreferenceCheckedIfPresent(perm.name, 143 group.areRuntimePermissionsGranted(new String[]{ perm.name })); 144 } 145 } else { 146 setPreferenceCheckedIfPresent(group.getName(), group.areRuntimePermissionsGranted()); 147 } 148 } 149 } 150 151 @Override 152 public void onPause() { 153 super.onPause(); 154 logAndClearToggledGroups(); 155 } 156 157 private void initializePermissionGroupList() { 158 final String packageName = mAppPermissions.getPackageInfo().packageName; 159 List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); 160 List<SwitchPreference> nonSystemPreferences = new ArrayList<>(); 161 162 if (!groups.isEmpty()) { 163 getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS)); 164 } 165 166 for (final AppPermissionGroup group : groups) { 167 if (!Utils.shouldShowPermission(group, packageName)) { 168 continue; 169 } 170 171 boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); 172 173 if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { 174 // If permission is controlled individually, we show all requested permission 175 // inside this group. 176 for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { 177 final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm); 178 showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 179 } 180 } else { 181 final SwitchPreference pref = createSwitchPreferenceForGroup(group); 182 showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 183 } 184 } 185 186 // Now add the non-system settings to the end of the list 187 for (SwitchPreference nonSystemPreference : nonSystemPreferences) { 188 getPreferenceScreen().addPreference(nonSystemPreference); 189 } 190 } 191 192 private void showOrAddToNonSystemPreferences(SwitchPreference pref, 193 List<SwitchPreference> nonSystemPreferences, // Mutate 194 boolean isPlatform) { 195 // The UI shows System settings first, then non-system settings 196 if (isPlatform) { 197 getPreferenceScreen().addPreference(pref); 198 } else { 199 nonSystemPreferences.add(pref); 200 } 201 } 202 203 private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group, 204 PermissionInfo perm) { 205 final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 206 pref.setKey(perm.name); 207 pref.setTitle(perm.loadLabel(mPackageManager)); 208 pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name })); 209 pref.setOnPreferenceChangeListener((p, newVal) -> { 210 if((Boolean) newVal) { 211 group.grantRuntimePermissions(false, new String[]{ perm.name }); 212 } else { 213 group.revokeRuntimePermissions(true, new String[]{ perm.name }); 214 } 215 return true; 216 }); 217 return pref; 218 } 219 220 private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) { 221 final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 222 223 pref.setKey(group.getName()); 224 pref.setTitle(group.getLabel()); 225 pref.setChecked(group.areRuntimePermissionsGranted()); 226 227 if (group.isPolicyFixed()) { 228 pref.setEnabled(false); 229 } else { 230 pref.setOnPreferenceChangeListener((p, newVal) -> { 231 if (LocationUtils.isLocationGroupAndProvider( 232 group.getName(), group.getApp().packageName)) { 233 LocationUtils.showLocationDialog( 234 getContext(), mAppPermissions.getAppLabel()); 235 return false; 236 } 237 238 if ((Boolean) newVal) { 239 setPermission(group, pref, true); 240 } else { 241 final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); 242 if (grantedByDefault 243 || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) { 244 new WearableDialogHelper.DialogBuilder(getContext()) 245 .setNegativeIcon(R.drawable.confirm_button) 246 .setPositiveIcon(R.drawable.cancel_button) 247 .setNegativeButton(R.string.grant_dialog_button_deny_anyway, 248 (dialog, which) -> { 249 setPermission(group, pref, false); 250 if (!group.hasGrantedByDefaultPermission()) { 251 mHasConfirmedRevoke = true; 252 } 253 }) 254 .setPositiveButton(R.string.cancel, (dialog, which) -> {}) 255 .setMessage(grantedByDefault ? 256 R.string.system_warning : R.string.old_sdk_deny_warning) 257 .show(); 258 return false; 259 } else { 260 setPermission(group, pref, false); 261 } 262 } 263 264 return true; 265 }); 266 } 267 return pref; 268 } 269 270 private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) { 271 if (grant) { 272 group.grantRuntimePermissions(false); 273 } else { 274 group.revokeRuntimePermissions(false); 275 } 276 addToggledGroup(group); 277 pref.setChecked(grant); 278 } 279 280 private void addToggledGroup(AppPermissionGroup group) { 281 if (mToggledGroups == null) { 282 mToggledGroups = new ArrayList<>(); 283 } 284 // Double toggle is back to initial state. 285 if (mToggledGroups.contains(group)) { 286 mToggledGroups.remove(group); 287 } else { 288 mToggledGroups.add(group); 289 } 290 } 291 292 private void logAndClearToggledGroups() { 293 if (mToggledGroups != null) { 294 String packageName = mAppPermissions.getPackageInfo().packageName; 295 SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups); 296 mToggledGroups = null; 297 } 298 } 299 300 private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) { 301 ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size()); 302 for(Permission perm : group.getPermissions()) { 303 try { 304 permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0)); 305 } catch (PackageManager.NameNotFoundException e) { 306 Log.w(LOG_TAG, "No permission:" + perm.getName()); 307 } 308 } 309 return permInfos; 310 } 311 312 private void setPreferenceCheckedIfPresent(String preferenceKey, boolean checked) { 313 Preference pref = findPreference(preferenceKey); 314 if (pref instanceof SwitchPreference) { 315 ((SwitchPreference) pref).setChecked(checked); 316 } 317 } 318} 319