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;
22df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.Intent;
23df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.pm.PackageInfo;
24df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.content.pm.PackageManager;
251019d73896ca8ec9baac1492c08443c7a6339380Shijian Liimport android.content.pm.PermissionInfo;
26df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.os.Bundle;
27df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport android.os.UserHandle;
28a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.Preference;
29a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.PreferenceFragment;
30df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport android.preference.PreferenceScreen;
31a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.preference.SwitchPreference;
32a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanimport android.support.wearable.view.WearableDialogHelper;
33df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.util.Log;
34df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.LayoutInflater;
35df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.View;
36df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.view.ViewGroup;
37df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport android.widget.Toast;
38df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
39df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.R;
40df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.model.AppPermissionGroup;
41df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.model.AppPermissions;
421019d73896ca8ec9baac1492c08443c7a6339380Shijian Liimport com.android.packageinstaller.permission.model.Permission;
43df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.utils.LocationUtils;
44df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport com.android.packageinstaller.permission.utils.SafetyNetLogger;
45275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Liimport com.android.packageinstaller.permission.utils.ArrayUtils;
46f9bf4f795615bac03d1b35a0138318473b1ef6bfSvet Ganovimport com.android.packageinstaller.permission.utils.Utils;
47df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport com.android.settingslib.RestrictedLockUtils;
48df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeonimport com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
49df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
50df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport java.util.ArrayList;
51df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hughimport java.util.List;
52df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
53a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwanpublic final class AppPermissionsFragmentWear extends PreferenceFragment {
54a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private static final String LOG_TAG = "AppPermFragWear";
55df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
56a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private static final String KEY_NO_PERMISSIONS = "no_permissions";
57df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
58df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    public static AppPermissionsFragmentWear newInstance(String packageName) {
59df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        return setPackageName(new AppPermissionsFragmentWear(), packageName);
60df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
61df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
62df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    private static <T extends Fragment> T setPackageName(T fragment, String packageName) {
63df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        Bundle arguments = new Bundle();
64df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
65df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        fragment.setArguments(arguments);
66df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        return fragment;
67df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
68df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
691019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    private PackageManager mPackageManager;
70a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private List<AppPermissionGroup> mToggledGroups;
71a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private AppPermissions mAppPermissions;
72a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan
73a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private boolean mHasConfirmedRevoke;
74a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan
75df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon    /**
76df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon     * Provides click behavior for disabled preferences.
77df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon     * We can't use {@link PreferenceFragment#onPreferenceTreeClick}, as the base
78df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon     * {@link SwitchPreference} doesn't delegate to that method if the preference is disabled.
79df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon     */
80df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon    private static class PermissionSwitchPreference extends SwitchPreference {
81df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon
82df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        private final Activity mActivity;
83df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon
84df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        public PermissionSwitchPreference(Activity activity) {
85df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon            super(activity);
86df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon            this.mActivity = activity;
87df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        }
88df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon
89df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        @Override
90df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        public void performClick(PreferenceScreen preferenceScreen) {
91df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon            super.performClick(preferenceScreen);
92df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon            if (!isEnabled()) {
93df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                // If setting the permission is disabled, it must have been locked
94df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                // by the device or profile owner. So get that info and pass it to
95df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                // the support details dialog.
96df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                EnforcedAdmin deviceOrProfileOwner = RestrictedLockUtils.getProfileOrDeviceOwner(
97df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                    mActivity, UserHandle.myUserId());
98df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
99df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon                    mActivity, deviceOrProfileOwner);
100df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon            }
101df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon        }
102df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon    }
103df5a889da09c2584ef143b02198f9e38b28a223fMatt McKeon
104df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    @Override
105df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    public void onCreate(Bundle savedInstanceState) {
106df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        super.onCreate(savedInstanceState);
107df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
108df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        String packageName = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
109df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        Activity activity = getActivity();
1101019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        mPackageManager = activity.getPackageManager();
1111019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
112df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        PackageInfo packageInfo;
113df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
114df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        try {
1151019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            packageInfo = mPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
116df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        } catch (PackageManager.NameNotFoundException e) {
117df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            Log.i(LOG_TAG, "No package:" + activity.getCallingPackage(), e);
118df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            packageInfo = null;
119df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
120df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
121df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        if (packageInfo == null) {
122df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            Toast.makeText(activity, R.string.app_not_found_dlg_title, Toast.LENGTH_LONG).show();
123df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            activity.finish();
124df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            return;
125df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
126df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
127a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        mAppPermissions = new AppPermissions(
128a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan                activity, packageInfo, null, true, () -> getActivity().finish());
129df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
130a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        addPreferencesFromResource(R.xml.watch_permissions);
131df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        initializePermissionGroupList();
132df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
133df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
134df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    @Override
135df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    public void onResume() {
136df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        super.onResume();
137df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        mAppPermissions.refresh();
138df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
139df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        // Also refresh the UI
140a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) {
1418bb255379818d819589fb8ee63927042a4464da2Shijian Li            if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) {
1428bb255379818d819589fb8ee63927042a4464da2Shijian Li                for (PermissionInfo perm : getPermissionInfosFromGroup(group)) {
1438bb255379818d819589fb8ee63927042a4464da2Shijian Li                    setPreferenceCheckedIfPresent(perm.name,
1448bb255379818d819589fb8ee63927042a4464da2Shijian Li                            group.areRuntimePermissionsGranted(new String[]{ perm.name }));
1458bb255379818d819589fb8ee63927042a4464da2Shijian Li                }
1468bb255379818d819589fb8ee63927042a4464da2Shijian Li            } else {
1478bb255379818d819589fb8ee63927042a4464da2Shijian Li                setPreferenceCheckedIfPresent(group.getName(), group.areRuntimePermissionsGranted());
148a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan            }
149df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
150df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
151df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
152df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    @Override
153a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    public void onPause() {
154a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        super.onPause();
155a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        logAndClearToggledGroups();
156df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
157df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
158df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    private void initializePermissionGroupList() {
159df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        final String packageName = mAppPermissions.getPackageInfo().packageName;
160df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups();
1611019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        List<SwitchPreference> nonSystemPreferences = new ArrayList<>();
162a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan
163a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        if (!groups.isEmpty()) {
164a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan            getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS));
165a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        }
166736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh
167a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        for (final AppPermissionGroup group : groups) {
168df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            if (!Utils.shouldShowPermission(group, packageName)) {
169df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh                continue;
170df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            }
171df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
172736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh            boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG);
173736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh
1741019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())) {
1751019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                // If permission is controlled individually, we show all requested permission
1761019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                // inside this group.
1771019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                for (PermissionInfo perm : getPermissionInfosFromGroup(group)) {
1781019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    final SwitchPreference pref = createSwitchPreferenceForPermission(group, perm);
1791019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform);
1801019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                }
181a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan            } else {
1821019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                final SwitchPreference pref = createSwitchPreferenceForGroup(group);
1831019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                showOrAddToNonSystemPreferences(pref, nonSystemPreferences, isPlatform);
1841019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            }
1851019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        }
186a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan
1871019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        // Now add the non-system settings to the end of the list
1881019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        for (SwitchPreference nonSystemPreference : nonSystemPreferences) {
1891019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            getPreferenceScreen().addPreference(nonSystemPreference);
1901019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        }
1911019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    }
192a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan
1931019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    private void showOrAddToNonSystemPreferences(SwitchPreference pref,
1941019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            List<SwitchPreference> nonSystemPreferences, // Mutate
1951019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            boolean isPlatform) {
1961019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        // The UI shows System settings first, then non-system settings
1971019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        if (isPlatform) {
1981019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            getPreferenceScreen().addPreference(pref);
1991019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        } else {
2001019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            nonSystemPreferences.add(pref);
2011019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        }
2021019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    }
203736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh
2041019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    private SwitchPreference createSwitchPreferenceForPermission(AppPermissionGroup group,
2051019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            PermissionInfo perm) {
2061019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        final SwitchPreference pref = new PermissionSwitchPreference(getActivity());
2071019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setKey(perm.name);
2081019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setTitle(perm.loadLabel(mPackageManager));
2091019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setChecked(group.areRuntimePermissionsGranted(new String[]{ perm.name }));
2101019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setOnPreferenceChangeListener((p, newVal) -> {
2111019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            if((Boolean) newVal) {
2121019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                group.grantRuntimePermissions(false, new String[]{ perm.name });
213736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh            } else {
214b8e4193e57bcaca51b08a88f3a67ef1d0641b75aShijian Li                group.revokeRuntimePermissions(true, new String[]{ perm.name });
215736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh            }
216275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li
217275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li            if (Utils.areGroupPermissionsIndividuallyControlled(getContext(), group.getName())
218275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                    && group.hasRuntimePermission()) {
219275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                // As long as one permission is changed in individually controlled group
220275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                // permissions, we will set user_fixed for non-granted permissions in that group.
221275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                // This avoids the system to automatically grant runtime permissions based on the
222275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                // fact that one of dangerous permission in that group is already granted.
223275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                String[] revokedPermissionsToFix = null;
224275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                final int permissionCount = group.getPermissions().size();
225275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li
226275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                for (int i = 0; i < permissionCount; i++) {
227275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                    Permission current = group.getPermissions().get(i);
228275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                    if (!current.isGranted() && !current.isUserFixed()) {
229275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                        revokedPermissionsToFix = ArrayUtils.appendString(
230275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                                revokedPermissionsToFix, current.getName());
231275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                    }
232275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                }
233275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li
234275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                if (revokedPermissionsToFix != null) {
235275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                    group.revokeRuntimePermissions(true, revokedPermissionsToFix);
236275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li                }
237275897a5a576e8d16ebc245c0a299c5d9448a5a6Shijian Li            }
2381019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            return true;
2391019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        });
2401019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        return pref;
2411019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    }
242736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh
2431019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    private SwitchPreference createSwitchPreferenceForGroup(AppPermissionGroup group) {
2441019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        final SwitchPreference pref = new PermissionSwitchPreference(getActivity());
2451019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
2461019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setKey(group.getName());
2471019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setTitle(group.getLabel());
2481019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        pref.setChecked(group.areRuntimePermissionsGranted());
2491019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
2501019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        if (group.isPolicyFixed()) {
2511019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            pref.setEnabled(false);
2521019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        } else {
2531019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            pref.setOnPreferenceChangeListener((p, newVal) -> {
2541019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                if (LocationUtils.isLocationGroupAndProvider(
2551019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                        group.getName(), group.getApp().packageName)) {
2561019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    LocationUtils.showLocationDialog(
2571019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                            getContext(), mAppPermissions.getAppLabel());
2581019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    return false;
2591019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                }
2601019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
2611019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                if ((Boolean) newVal) {
2621019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    setPermission(group, pref, true);
2631019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                } else {
2641019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    final boolean grantedByDefault = group.hasGrantedByDefaultPermission();
2651019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    if (grantedByDefault
2661019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                            || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) {
2671019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                        new WearableDialogHelper.DialogBuilder(getContext())
2681019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .setNegativeIcon(R.drawable.confirm_button)
2691019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .setPositiveIcon(R.drawable.cancel_button)
2701019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .setNegativeButton(R.string.grant_dialog_button_deny_anyway,
2711019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                        (dialog, which) -> {
2721019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                            setPermission(group, pref, false);
2731019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                            if (!group.hasGrantedByDefaultPermission()) {
2741019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                                mHasConfirmedRevoke = true;
2751019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                            }
2761019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                        })
2771019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .setPositiveButton(R.string.cancel, (dialog, which) -> {})
2781019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .setMessage(grantedByDefault ?
2791019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                        R.string.system_warning : R.string.old_sdk_deny_warning)
2801019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                                .show();
2811019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                        return false;
2821019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    } else {
2831019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                        setPermission(group, pref, false);
2841019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                    }
2851019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                }
2861019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
2871019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                return true;
2881019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            });
289df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
2901019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        return pref;
291df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
292df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
293a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan    private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) {
294a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        if (grant) {
295df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            group.grantRuntimePermissions(false);
296df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        } else {
297a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan            group.revokeRuntimePermissions(false);
2984b7427563d334dab50eb77028a78e709ea58880bAnthony Hugh        }
299a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        addToggledGroup(group);
300a5d853c3bd4e4e84872fc802decd18e9c18408d2Michael Kwan        pref.setChecked(grant);
301df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
302df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
303df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    private void addToggledGroup(AppPermissionGroup group) {
304df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        if (mToggledGroups == null) {
305df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            mToggledGroups = new ArrayList<>();
306df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
307df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        // Double toggle is back to initial state.
308df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        if (mToggledGroups.contains(group)) {
309df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            mToggledGroups.remove(group);
310df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        } else {
311df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            mToggledGroups.add(group);
312df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
313df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
314df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh
315736c82ba577f8f972ea4277357ae440b192dcd13Anthony Hugh    private void logAndClearToggledGroups() {
316df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        if (mToggledGroups != null) {
317df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            String packageName = mAppPermissions.getPackageInfo().packageName;
318df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            SafetyNetLogger.logPermissionsToggled(packageName, mToggledGroups);
319df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh            mToggledGroups = null;
320df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh        }
321df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh    }
3221019d73896ca8ec9baac1492c08443c7a6339380Shijian Li
3231019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    private List<PermissionInfo> getPermissionInfosFromGroup(AppPermissionGroup group) {
3241019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        ArrayList<PermissionInfo> permInfos = new ArrayList<>(group.getPermissions().size());
3251019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        for(Permission perm : group.getPermissions()) {
3261019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            try {
3271019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                permInfos.add(mPackageManager.getPermissionInfo(perm.getName(), 0));
3281019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            } catch (PackageManager.NameNotFoundException e) {
3291019d73896ca8ec9baac1492c08443c7a6339380Shijian Li                Log.w(LOG_TAG, "No permission:" + perm.getName());
3301019d73896ca8ec9baac1492c08443c7a6339380Shijian Li            }
3311019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        }
3321019d73896ca8ec9baac1492c08443c7a6339380Shijian Li        return permInfos;
3331019d73896ca8ec9baac1492c08443c7a6339380Shijian Li    }
3348bb255379818d819589fb8ee63927042a4464da2Shijian Li
3358bb255379818d819589fb8ee63927042a4464da2Shijian Li    private void setPreferenceCheckedIfPresent(String preferenceKey, boolean checked) {
3368bb255379818d819589fb8ee63927042a4464da2Shijian Li        Preference pref = findPreference(preferenceKey);
3378bb255379818d819589fb8ee63927042a4464da2Shijian Li        if (pref instanceof SwitchPreference) {
3388bb255379818d819589fb8ee63927042a4464da2Shijian Li            ((SwitchPreference) pref).setChecked(checked);
3398bb255379818d819589fb8ee63927042a4464da2Shijian Li        }
3408bb255379818d819589fb8ee63927042a4464da2Shijian Li    }
341df4d4542c2cf2fa0a7539412af2a99d60b1c2a15Anthony Hugh}
342