1df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh/* 2df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* Copyright (C) 2015 The Android Open Source Project 3df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* 4df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* Licensed under the Apache License, Version 2.0 (the "License"); 5df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* you may not use this file except in compliance with the License. 6df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* You may obtain a copy of the License at 7df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* 8df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* http://www.apache.org/licenses/LICENSE-2.0 9df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* 10df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* Unless required by applicable law or agreed to in writing, software 11df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* distributed under the License is distributed on an "AS IS" BASIS, 12df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* See the License for the specific language governing permissions and 14df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh* limitations under the License. 15df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh*/ 16df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 17df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughpackage com.android.packageinstaller.permission.ui.wear; 18df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 190c49c07f1c83e9998fa0af2cd157633644358611Anthony Hughimport android.Manifest; 20df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.app.Activity; 21df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.app.Fragment; 228c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Liimport android.content.DialogInterface; 23df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.Intent; 24df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.pm.PackageInfo; 25df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.pm.PackageManager; 262ee04f47e459def569b1f719efd97456634024d4Shijian Liimport android.content.pm.PermissionInfo; 2721aa367b683cf35661f526bf8a6530013d5e862aShijian Liimport android.os.Build; 28df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.os.Bundle; 29df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport android.os.UserHandle; 30a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.Preference; 31a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.PreferenceFragment; 32df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport android.preference.PreferenceScreen; 33a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.SwitchPreference; 34a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.support.wearable.view.WearableDialogHelper; 35df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.util.Log; 36df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.LayoutInflater; 37df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.View; 38df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.ViewGroup; 39df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.widget.Toast; 40df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 41df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.R; 42df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.model.AppPermissionGroup; 43df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.model.AppPermissions; 442ee04f47e459def569b1f719efd97456634024d4Shijian Liimport com.android.packageinstaller.permission.model.Permission; 45b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Liimport com.android.packageinstaller.permission.utils.ArrayUtils; 46df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.utils.LocationUtils; 47df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.utils.SafetyNetLogger; 48f9bf4f795615bac03d1b35a0138318473b1ef6bfSvet Ganovimport com.android.packageinstaller.permission.utils.Utils; 49df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport com.android.settingslib.RestrictedLockUtils; 50df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 51df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 52df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport java.util.ArrayList; 53df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport java.util.List; 54df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 55a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanpublic final class AppPermissionsFragmentWear extends PreferenceFragment { 56a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private static final String LOG_TAG = "AppPermFragWear"; 57df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 58a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private static final String KEY_NO_PERMISSIONS = "no_permissions"; 59df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 60df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh public static AppPermissionsFragmentWear newInstance(String packageName) { 61df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh return setPackageName(new AppPermissionsFragmentWear(), packageName); 62df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 63df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 64df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh private static <T extends Fragment> T setPackageName(T fragment, String packageName) { 65df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh Bundle arguments = new Bundle(); 66df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName); 67df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh fragment.setArguments(arguments); 68df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh return fragment; 69df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 70df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 712ee04f47e459def569b1f719efd97456634024d4Shijian Li private PackageManager mPackageManager; 72a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private List<AppPermissionGroup> mToggledGroups; 73a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private AppPermissions mAppPermissions; 74a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan 75a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private boolean mHasConfirmedRevoke; 76a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan 77df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon /** 78df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon * Provides click behavior for disabled preferences. 79df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon * We can't use {@link PreferenceFragment#onPreferenceTreeClick}, as the base 80df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon * {@link SwitchPreference} doesn't delegate to that method if the preference is disabled. 81df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon */ 82df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon private static class PermissionSwitchPreference extends SwitchPreference { 83df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon 84df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon private final Activity mActivity; 85df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon 86df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon public PermissionSwitchPreference(Activity activity) { 87df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon super(activity); 88df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon this.mActivity = activity; 89df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon } 90df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon 91df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon @Override 92df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon public void performClick(PreferenceScreen preferenceScreen) { 93df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon super.performClick(preferenceScreen); 94df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon if (!isEnabled()) { 95df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon // If setting the permission is disabled, it must have been locked 96df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon // by the device or profile owner. So get that info and pass it to 97df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon // the support details dialog. 98df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon EnforcedAdmin deviceOrProfileOwner = RestrictedLockUtils.getProfileOrDeviceOwner( 99df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon mActivity, UserHandle.myUserId()); 100df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon RestrictedLockUtils.sendShowAdminSupportDetailsIntent( 101df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon mActivity, deviceOrProfileOwner); 102df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon } 103df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon } 104df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon } 105df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon 106df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh @Override 107df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh public void onCreate(Bundle savedInstanceState) { 108df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh super.onCreate(savedInstanceState); 109df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 110df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME); 111df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh Activity activity = getActivity(); 1122ee04f47e459def569b1f719efd97456634024d4Shijian Li mPackageManager = activity.getPackageManager(); 1132ee04f47e459def569b1f719efd97456634024d4Shijian Li 114df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh PackageInfo packageInfo; 115df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 116df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh try { 1172ee04f47e459def569b1f719efd97456634024d4Shijian Li packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); 118df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } catch (PackageManager.NameNotFoundException e) { 119df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e); 120df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh packageInfo = null; 121df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 122df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 123df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh if (packageInfo == null) { 124df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show(); 125df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh activity.finish(); 126df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh return; 127df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 128df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 129a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan mAppPermissions = new AppPermissions( 130a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan activity, packageInfo, null, true, () -> getActivity().finish()); 131df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 132a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan addPreferencesFromResource(R.xml.watch_permissions); 133df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh initializePermissionGroupList(); 134df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 135df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 136df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh @Override 137df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh public void onResume() { 138df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh super.onResume(); 139df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh mAppPermissions.refresh(); 140df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 141df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh // Also refresh the UI 142a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { 1438bb255379818d819589fb8ee63927042a4464da2Shijian Li if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { 1448bb255379818d819589fb8ee63927042a4464da2Shijian Li for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { 1458bb255379818d819589fb8ee63927042a4464da2Shijian Li setPreferenceCheckedIfPresent(perm.name, 1468bb255379818d819589fb8ee63927042a4464da2Shijian Li group.areRuntimePermissionsGranted(new String[]{ perm.name })); 1478bb255379818d819589fb8ee63927042a4464da2Shijian Li } 1488bb255379818d819589fb8ee63927042a4464da2Shijian Li } else { 1498bb255379818d819589fb8ee63927042a4464da2Shijian Li setPreferenceCheckedIfPresent(group.getName(), group.areRuntimePermissionsGranted()); 150a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan } 151df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 152df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 153df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 154df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh @Override 155a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan public void onPause() { 156a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan super.onPause(); 157a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan logAndClearToggledGroups(); 158df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 159df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 160df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh private void initializePermissionGroupList() { 161df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh final String packageName = mAppPermissions.getPackageInfo().packageName; 162df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); 1632ee04f47e459def569b1f719efd97456634024d4Shijian Li List<SwitchPreference> nonSystemPreferences = new ArrayList<>(); 164a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan 165a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan if (!groups.isEmpty()) { 166a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS)); 167a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan } 168736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh 169a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan for (final AppPermissionGroup group : groups) { 170df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh if (!Utils.shouldShowPermission(group, packageName)) { 171df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh continue; 172df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 173df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 174736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); 175736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh 1762ee04f47e459def569b1f719efd97456634024d4Shijian Li if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) { 1772ee04f47e459def569b1f719efd97456634024d4Shijian Li // If permission is controlled individually, we show all requested permission 1782ee04f47e459def569b1f719efd97456634024d4Shijian Li // inside this group. 1792ee04f47e459def569b1f719efd97456634024d4Shijian Li for (PermissionInfo perm : getPermissionInfosFromGroup(group)) { 1802ee04f47e459def569b1f719efd97456634024d4Shijian Li final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm); 1812ee04f47e459def569b1f719efd97456634024d4Shijian Li showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 1822ee04f47e459def569b1f719efd97456634024d4Shijian Li } 183a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan } else { 1842ee04f47e459def569b1f719efd97456634024d4Shijian Li final SwitchPreference pref = createSwitchPreferenceForGroup(group); 1852ee04f47e459def569b1f719efd97456634024d4Shijian Li showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform); 1862ee04f47e459def569b1f719efd97456634024d4Shijian Li } 1872ee04f47e459def569b1f719efd97456634024d4Shijian Li } 188a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan 1892ee04f47e459def569b1f719efd97456634024d4Shijian Li // Now add the non-system settings to the end of the list 1902ee04f47e459def569b1f719efd97456634024d4Shijian Li for (SwitchPreference nonSystemPreference : nonSystemPreferences) { 1912ee04f47e459def569b1f719efd97456634024d4Shijian Li getPreferenceScreen().addPreference(nonSystemPreference); 1922ee04f47e459def569b1f719efd97456634024d4Shijian Li } 1932ee04f47e459def569b1f719efd97456634024d4Shijian Li } 194a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan 1952ee04f47e459def569b1f719efd97456634024d4Shijian Li private void showOrAddToNonSystemPreferences(SwitchPreference pref, 1962ee04f47e459def569b1f719efd97456634024d4Shijian Li List<SwitchPreference> nonSystemPreferences, // Mutate 1972ee04f47e459def569b1f719efd97456634024d4Shijian Li boolean isPlatform) { 1982ee04f47e459def569b1f719efd97456634024d4Shijian Li // The UI shows System settings first, then non-system settings 1992ee04f47e459def569b1f719efd97456634024d4Shijian Li if (isPlatform) { 2002ee04f47e459def569b1f719efd97456634024d4Shijian Li getPreferenceScreen().addPreference(pref); 2012ee04f47e459def569b1f719efd97456634024d4Shijian Li } else { 2022ee04f47e459def569b1f719efd97456634024d4Shijian Li nonSystemPreferences.add(pref); 2032ee04f47e459def569b1f719efd97456634024d4Shijian Li } 2042ee04f47e459def569b1f719efd97456634024d4Shijian Li } 205736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh 2062ee04f47e459def569b1f719efd97456634024d4Shijian Li private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group, 2072ee04f47e459def569b1f719efd97456634024d4Shijian Li PermissionInfo perm) { 2082ee04f47e459def569b1f719efd97456634024d4Shijian Li final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 2092ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setKey(perm.name); 2102ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setTitle(perm.loadLabel(mPackageManager)); 2112ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name })); 2122ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setOnPreferenceChangeListener((p, newVal) -> { 2132ee04f47e459def569b1f719efd97456634024d4Shijian Li if((Boolean) newVal) { 2142ee04f47e459def569b1f719efd97456634024d4Shijian Li group.grantRuntimePermissions(false, new String[]{ perm.name }); 215b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li 216b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName()) 217b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li && group.doesSupportRuntimePermissions()) { 218b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // We are granting a permission from a group but since this is an 219b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // individual permission control other permissions in the group may 220b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // be revoked, hence we need to mark them user fixed to prevent the 221b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // app from requesting a non-granted permission and it being granted 222b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // because another permission in the group is granted. This applies 223b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // only to apps that support runtime permissions. 224b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li String[] revokedPermissionsToFix = null; 225b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li final int permissionCount = group.getPermissions().size(); 226b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li 227b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li for (int i = 0; i < permissionCount; i++) { 228b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li Permission current = group.getPermissions().get(i); 229b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li if (!current.isGranted() && !current.isUserFixed()) { 230b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li revokedPermissionsToFix = ArrayUtils.appendString( 231b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li revokedPermissionsToFix, current.getName()); 232b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li } 233b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li } 234b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li 235b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li if (revokedPermissionsToFix != null) { 236b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li // If some permissions were not granted then they should be fixed. 237b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li group.revokeRuntimePermissions(true, revokedPermissionsToFix); 238b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li } 239b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li } 240736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh } else { 24121aa367b683cf35661f526bf8a6530013d5e862aShijian Li final Permission appPerm = getPermissionFromGroup(group, perm.name); 24221aa367b683cf35661f526bf8a6530013d5e862aShijian Li if (appPerm == null) { 24321aa367b683cf35661f526bf8a6530013d5e862aShijian Li return false; 24421aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 245b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li 24621aa367b683cf35661f526bf8a6530013d5e862aShijian Li final boolean grantedByDefault = appPerm.isGrantedByDefault(); 24721aa367b683cf35661f526bf8a6530013d5e862aShijian Li if (grantedByDefault 24821aa367b683cf35661f526bf8a6530013d5e862aShijian Li || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) { 2498c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li showRevocationWarningDialog( 2508c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li (dialog, which) -> { 2518c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li revokePermissionInGroup(group, perm.name); 2528c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li pref.setChecked(false); 2538c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li if (!appPerm.isGrantedByDefault()) { 2548c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li mHasConfirmedRevoke = true; 2558c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li } 2568c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li }, 2578c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li grantedByDefault 2588c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li ? R.string.system_warning 2598c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li : R.string.old_sdk_deny_warning); 26021aa367b683cf35661f526bf8a6530013d5e862aShijian Li return false; 26121aa367b683cf35661f526bf8a6530013d5e862aShijian Li } else { 26221aa367b683cf35661f526bf8a6530013d5e862aShijian Li revokePermissionInGroup(group, perm.name); 263b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li } 264736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh } 265b9c42135abb652b0595f0636fbadfe5e738f9e95Shijian Li 2662ee04f47e459def569b1f719efd97456634024d4Shijian Li return true; 2672ee04f47e459def569b1f719efd97456634024d4Shijian Li }); 2682ee04f47e459def569b1f719efd97456634024d4Shijian Li return pref; 2692ee04f47e459def569b1f719efd97456634024d4Shijian Li } 2701019d73896ca8ec9baac1492c08443c7a6339380Shijian Li 2718c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li private void showRevocationWarningDialog( 2728c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li DialogInterface.OnClickListener confirmListener, 2738c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li int warningMessageId) { 2748c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li new WearableDialogHelper.DialogBuilder(getContext()) 2758c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .setNegativeIcon(R.drawable.confirm_button) 2768c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .setPositiveIcon(R.drawable.cancel_button) 2778c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .setNegativeButton(R.string.grant_dialog_button_deny_anyway, confirmListener) 2788c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .setPositiveButton(R.string.cancel, null) 2798c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .setMessage(warningMessageId) 2808c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li .show(); 2818c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li } 2828c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li 28321aa367b683cf35661f526bf8a6530013d5e862aShijian Li private static Permission getPermissionFromGroup(AppPermissionGroup group, String permName) { 28421aa367b683cf35661f526bf8a6530013d5e862aShijian Li final int permissionCount = group.getPermissions().size(); 28521aa367b683cf35661f526bf8a6530013d5e862aShijian Li 28621aa367b683cf35661f526bf8a6530013d5e862aShijian Li for (int i = 0; i < permissionCount; i++) { 28721aa367b683cf35661f526bf8a6530013d5e862aShijian Li Permission currentPerm = group.getPermissions().get(i); 28821aa367b683cf35661f526bf8a6530013d5e862aShijian Li if(currentPerm.getName().equals(permName)) { 28921aa367b683cf35661f526bf8a6530013d5e862aShijian Li return currentPerm; 29021aa367b683cf35661f526bf8a6530013d5e862aShijian Li }; 29121aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 29221aa367b683cf35661f526bf8a6530013d5e862aShijian Li 29321aa367b683cf35661f526bf8a6530013d5e862aShijian Li if ("user".equals(Build.TYPE)) { 29421aa367b683cf35661f526bf8a6530013d5e862aShijian Li Log.e(LOG_TAG, String.format("The impossible happens, permission %s is not in group %s.", 29521aa367b683cf35661f526bf8a6530013d5e862aShijian Li permName, group.getName())); 29621aa367b683cf35661f526bf8a6530013d5e862aShijian Li return null; 29721aa367b683cf35661f526bf8a6530013d5e862aShijian Li } else { 29821aa367b683cf35661f526bf8a6530013d5e862aShijian Li // This is impossible, throw a fatal error in non-user build. 29921aa367b683cf35661f526bf8a6530013d5e862aShijian Li throw new IllegalArgumentException( 30021aa367b683cf35661f526bf8a6530013d5e862aShijian Li String.format("Permission %s is not in group %s", permName, group.getName())); 30121aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 30221aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 30321aa367b683cf35661f526bf8a6530013d5e862aShijian Li 30421aa367b683cf35661f526bf8a6530013d5e862aShijian Li private void revokePermissionInGroup(AppPermissionGroup group, String permName) { 30521aa367b683cf35661f526bf8a6530013d5e862aShijian Li group.revokeRuntimePermissions(true, new String[]{ permName }); 30621aa367b683cf35661f526bf8a6530013d5e862aShijian Li 30721aa367b683cf35661f526bf8a6530013d5e862aShijian Li if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName()) 30821aa367b683cf35661f526bf8a6530013d5e862aShijian Li && group.doesSupportRuntimePermissions() 30921aa367b683cf35661f526bf8a6530013d5e862aShijian Li && !group.areRuntimePermissionsGranted()) { 31021aa367b683cf35661f526bf8a6530013d5e862aShijian Li // If we just revoked the last permission we need to clear 31121aa367b683cf35661f526bf8a6530013d5e862aShijian Li // the user fixed state as now the app should be able to 31221aa367b683cf35661f526bf8a6530013d5e862aShijian Li // request them at runtime if supported. 31321aa367b683cf35661f526bf8a6530013d5e862aShijian Li group.revokeRuntimePermissions(false); 31421aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 31521aa367b683cf35661f526bf8a6530013d5e862aShijian Li } 31621aa367b683cf35661f526bf8a6530013d5e862aShijian Li 3172ee04f47e459def569b1f719efd97456634024d4Shijian Li private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) { 3182ee04f47e459def569b1f719efd97456634024d4Shijian Li final SwitchPreference pref = new PermissionSwitchPreference(getActivity()); 3192ee04f47e459def569b1f719efd97456634024d4Shijian Li 3202ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setKey(group.getName()); 3212ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setTitle(group.getLabel()); 3222ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setChecked(group.areRuntimePermissionsGranted()); 3232ee04f47e459def569b1f719efd97456634024d4Shijian Li 3242ee04f47e459def569b1f719efd97456634024d4Shijian Li if (group.isPolicyFixed()) { 3252ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setEnabled(false); 3262ee04f47e459def569b1f719efd97456634024d4Shijian Li } else { 3272ee04f47e459def569b1f719efd97456634024d4Shijian Li pref.setOnPreferenceChangeListener((p, newVal) -> { 3282ee04f47e459def569b1f719efd97456634024d4Shijian Li if (LocationUtils.isLocationGroupAndProvider( 3292ee04f47e459def569b1f719efd97456634024d4Shijian Li group.getName(), group.getApp().packageName)) { 3302ee04f47e459def569b1f719efd97456634024d4Shijian Li LocationUtils.showLocationDialog( 3312ee04f47e459def569b1f719efd97456634024d4Shijian Li getContext(), mAppPermissions.getAppLabel()); 3322ee04f47e459def569b1f719efd97456634024d4Shijian Li return false; 3332ee04f47e459def569b1f719efd97456634024d4Shijian Li } 3342ee04f47e459def569b1f719efd97456634024d4Shijian Li 3352ee04f47e459def569b1f719efd97456634024d4Shijian Li if ((Boolean) newVal) { 3362ee04f47e459def569b1f719efd97456634024d4Shijian Li setPermission(group, pref, true); 3372ee04f47e459def569b1f719efd97456634024d4Shijian Li } else { 3382ee04f47e459def569b1f719efd97456634024d4Shijian Li final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); 3392ee04f47e459def569b1f719efd97456634024d4Shijian Li if (grantedByDefault 3402ee04f47e459def569b1f719efd97456634024d4Shijian Li || (!group.doesSupportRuntimePermissions() && !mHasConfirmedRevoke)) { 3418c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li showRevocationWarningDialog( 3428c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li (dialog, which) -> { 3438c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li setPermission(group, pref, false); 3448c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li if (!group.hasGrantedByDefaultPermission()) { 3458c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li mHasConfirmedRevoke = true; 3468c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li } 3478c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li }, 3488c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li grantedByDefault 3498c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li ? R.string.system_warning 3508c6525e3599121ce1e99ba5d45133d0969b513e0Shijian Li : R.string.old_sdk_deny_warning); 3512ee04f47e459def569b1f719efd97456634024d4Shijian Li return false; 3522ee04f47e459def569b1f719efd97456634024d4Shijian Li } else { 3532ee04f47e459def569b1f719efd97456634024d4Shijian Li setPermission(group, pref, false); 3542ee04f47e459def569b1f719efd97456634024d4Shijian Li } 3552ee04f47e459def569b1f719efd97456634024d4Shijian Li } 3562ee04f47e459def569b1f719efd97456634024d4Shijian Li 3572ee04f47e459def569b1f719efd97456634024d4Shijian Li return true; 3582ee04f47e459def569b1f719efd97456634024d4Shijian Li }); 359df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 3602ee04f47e459def569b1f719efd97456634024d4Shijian Li return pref; 361df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 362df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 363a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) { 364a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan if (grant) { 365df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh group.grantRuntimePermissions(false); 366df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } else { 367a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan group.revokeRuntimePermissions(false); 3684b7427563d334dab50eb77028a78e709ea58880bAnthony Hugh } 369a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan addToggledGroup(group); 370a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan pref.setChecked(grant); 371df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 372df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 373df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh private void addToggledGroup(AppPermissionGroup group) { 374df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh if (mToggledGroups == null) { 375df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh mToggledGroups = new ArrayList<>(); 376df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 377df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh // Double toggle is back to initial state. 378df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh if (mToggledGroups.contains(group)) { 379df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh mToggledGroups.remove(group); 380df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } else { 381df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh mToggledGroups.add(group); 382df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 383df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 384df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh 385736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh private void logAndClearToggledGroups() { 386df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh if (mToggledGroups != null) { 387df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh String packageName = mAppPermissions.getPackageInfo().packageName; 388df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups); 389df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh mToggledGroups = null; 390df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 391df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh } 3922ee04f47e459def569b1f719efd97456634024d4Shijian Li 3932ee04f47e459def569b1f719efd97456634024d4Shijian Li private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) { 3942ee04f47e459def569b1f719efd97456634024d4Shijian Li ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size()); 3952ee04f47e459def569b1f719efd97456634024d4Shijian Li for(Permission perm : group.getPermissions()) { 3962ee04f47e459def569b1f719efd97456634024d4Shijian Li try { 3972ee04f47e459def569b1f719efd97456634024d4Shijian Li permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0)); 3982ee04f47e459def569b1f719efd97456634024d4Shijian Li } catch (PackageManager.NameNotFoundException e) { 3992ee04f47e459def569b1f719efd97456634024d4Shijian Li Log.w(LOG_TAG, "No permission:" + perm.getName()); 4002ee04f47e459def569b1f719efd97456634024d4Shijian Li } 4012ee04f47e459def569b1f719efd97456634024d4Shijian Li } 4022ee04f47e459def569b1f719efd97456634024d4Shijian Li return permInfos; 4032ee04f47e459def569b1f719efd97456634024d4Shijian Li } 4048bb255379818d819589fb8ee63927042a4464da2Shijian Li 4058bb255379818d819589fb8ee63927042a4464da2Shijian Li private void setPreferenceCheckedIfPresent(String preferenceKey, boolean checked) { 4068bb255379818d819589fb8ee63927042a4464da2Shijian Li Preference pref = findPreference(preferenceKey); 4078bb255379818d819589fb8ee63927042a4464da2Shijian Li if (pref instanceof SwitchPreference) { 4088bb255379818d819589fb8ee63927042a4464da2Shijian Li ((SwitchPreference) pref).setChecked(checked); 4098bb255379818d819589fb8ee63927042a4464da2Shijian Li } 4108bb255379818d819589fb8ee63927042a4464da2Shijian Li } 411df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh} 412