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