AppPermissionsFragmentWear.java revision 1019d73896ca8ec9baac1492c08443c7a6339380
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 Preference pref = findPreference(group.getName()); 141 if (pref instanceof SwitchPreference) { 142 ((SwitchPreference) pref).setChecked(group.areRuntimePermissionsGranted()); 143 } 144 } 145 } 146 147 @Override 148 public void onPause() { 149 super.onPause(); 150 logAndClearToggledGroups(); 151 } 152 153 private void initializePermissionGroupList() { 154 final String packageName = mAppPermissions.getPackageInfo().packageName; 155 List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); 156 List<SwitchPreference> nonSystemPreferences = new ArrayList<>(); 157 158 if (!groups.isEmpty()) { 159 getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS)); 160 } 161 162 for (final AppPermissionGroup group : groups) { 163 if (!Utils.shouldShowPermission(group, packageName)) { 164 continue; 165 } 166 167 boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); 168 169 if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { 170 // If permission is controlled individually, we show all requested permission 171 // inside this group. 172 for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { 173 final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm); 174 showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 175 } 176 } else { 177 final SwitchPreference pref = createSwitchPreferenceForGroup(group); 178 showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 179 } 180 } 181 182 // Now add the non-system settings to the end of the list 183 for (SwitchPreference nonSystemPreference : nonSystemPreferences) { 184 getPreferenceScreen().addPreference(nonSystemPreference); 185 } 186 } 187 188 private void showOrAddToNonSystemPreferences(SwitchPreference pref, 189 List<SwitchPreference> nonSystemPreferences, // Mutate 190 boolean isPlatform) { 191 // The UI shows System settings first, then non-system settings 192 if (isPlatform) { 193 getPreferenceScreen().addPreference(pref); 194 } else { 195 nonSystemPreferences.add(pref); 196 } 197 } 198 199 private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group, 200 PermissionInfo perm) { 201 final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 202 pref.setKey(perm.name); 203 pref.setTitle(perm.loadLabel(mPackageManager)); 204 pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name })); 205 pref.setOnPreferenceChangeListener((p, newVal) -> { 206 if((Boolean) newVal) { 207 group.grantRuntimePermissions(false, new String[]{ perm.name }); 208 } else { 209 group.revokeRuntimePermissions(true, new String[]{ perm.name }); 210 } 211 return true; 212 }); 213 return pref; 214 } 215 216 private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) { 217 final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 218 219 pref.setKey(group.getName()); 220 pref.setTitle(group.getLabel()); 221 pref.setChecked(group.areRuntimePermissionsGranted()); 222 223 if (group.isPolicyFixed()) { 224 pref.setEnabled(false); 225 } else { 226 pref.setOnPreferenceChangeListener((p, newVal) -> { 227 if (LocationUtils.isLocationGroupAndProvider( 228 group.getName(), group.getApp().packageName)) { 229 LocationUtils.showLocationDialog( 230 getContext(), mAppPermissions.getAppLabel()); 231 return false; 232 } 233 234 if ((Boolean) newVal) { 235 setPermission(group, pref, true); 236 } else { 237 final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); 238 if (grantedByDefault 239 || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) { 240 new WearableDialogHelper.DialogBuilder(getContext()) 241 .setNegativeIcon(R.drawable.confirm_button) 242 .setPositiveIcon(R.drawable.cancel_button) 243 .setNegativeButton(R.string.grant_dialog_button_deny_anyway, 244 (dialog, which) -> { 245 setPermission(group, pref, false); 246 if (!group.hasGrantedByDefaultPermission()) { 247 mHasConfirmedRevoke = true; 248 } 249 }) 250 .setPositiveButton(R.string.cancel, (dialog, which) -> {}) 251 .setMessage(grantedByDefault ? 252 R.string.system_warning : R.string.old_sdk_deny_warning) 253 .show(); 254 return false; 255 } else { 256 setPermission(group, pref, false); 257 } 258 } 259 260 return true; 261 }); 262 } 263 return pref; 264 } 265 266 private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) { 267 if (grant) { 268 group.grantRuntimePermissions(false); 269 } else { 270 group.revokeRuntimePermissions(false); 271 } 272 addToggledGroup(group); 273 pref.setChecked(grant); 274 } 275 276 private void addToggledGroup(AppPermissionGroup group) { 277 if (mToggledGroups == null) { 278 mToggledGroups = new ArrayList<>(); 279 } 280 // Double toggle is back to initial state. 281 if (mToggledGroups.contains(group)) { 282 mToggledGroups.remove(group); 283 } else { 284 mToggledGroups.add(group); 285 } 286 } 287 288 private void logAndClearToggledGroups() { 289 if (mToggledGroups != null) { 290 String packageName = mAppPermissions.getPackageInfo().packageName; 291 SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups); 292 mToggledGroups = null; 293 } 294 } 295 296 private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) { 297 ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size()); 298 for(Permission perm : group.getPermissions()) { 299 try { 300 permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0)); 301 } catch (PackageManager.NameNotFoundException e) { 302 Log.w(LOG_TAG, "No permission:" + perm.getName()); 303 } 304 } 305 return permInfos; 306 } 307} 308