• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 package com.android.packageinstaller.permission.ui.television;
18 
19 import android.Manifest;
20 import android.app.ActionBar;
21 import android.app.AlertDialog;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.PackageItemInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.content.pm.PermissionGroupInfo;
30 import android.content.pm.PermissionInfo;
31 import android.graphics.drawable.Drawable;
32 import android.net.Uri;
33 import android.os.Build;
34 import android.os.Bundle;
35 import android.provider.Settings;
36 import android.util.Log;
37 import android.view.MenuItem;
38 
39 import androidx.preference.Preference;
40 import androidx.preference.Preference.OnPreferenceChangeListener;
41 import androidx.preference.Preference.OnPreferenceClickListener;
42 import androidx.preference.PreferenceCategory;
43 import androidx.preference.PreferenceGroup;
44 import androidx.preference.SwitchPreference;
45 
46 import com.android.packageinstaller.permission.model.AppPermissionGroup;
47 import com.android.packageinstaller.permission.model.AppPermissions;
48 import com.android.packageinstaller.permission.utils.Utils;
49 import com.android.permissioncontroller.R;
50 
51 import java.util.ArrayList;
52 import java.util.Collections;
53 import java.util.Comparator;
54 
55 public final class AllAppPermissionsFragment extends SettingsWithHeader {
56 
57     private static final String LOG_TAG = "AllAppPermissionsFragment";
58 
59     private static final String KEY_OTHER = "other_perms";
60 
61     private PackageInfo mPackageInfo;
62 
63     private AppPermissions mAppPermissions;
64 
newInstance(String packageName)65     public static AllAppPermissionsFragment newInstance(String packageName) {
66         AllAppPermissionsFragment instance = new AllAppPermissionsFragment();
67         Bundle arguments = new Bundle();
68         arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
69         instance.setArguments(arguments);
70         return instance;
71     }
72 
73     @Override
onCreate(Bundle savedInstanceState)74     public void onCreate(Bundle savedInstanceState) {
75         super.onCreate(savedInstanceState);
76         setHasOptionsMenu(true);
77         final ActionBar ab = getActivity().getActionBar();
78         if (ab != null) {
79             ab.setTitle(R.string.all_permissions);
80             ab.setDisplayHomeAsUpEnabled(true);
81         }
82 
83         String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
84         try {
85             mPackageInfo = getActivity().getPackageManager().getPackageInfo(pkg,
86                     PackageManager.GET_PERMISSIONS);
87         } catch (NameNotFoundException e) {
88             getActivity().finish();
89         }
90 
91         mAppPermissions = new AppPermissions(getActivity(), mPackageInfo, false,
92                 new Runnable() {
93             @Override
94             public void run() {
95                 getActivity().finish();
96             }
97         });
98     }
99 
100     @Override
onResume()101     public void onResume() {
102         super.onResume();
103         updateUi();
104     }
105 
106     @Override
onOptionsItemSelected(MenuItem item)107     public boolean onOptionsItemSelected(MenuItem item) {
108         switch (item.getItemId()) {
109             case android.R.id.home: {
110                 getFragmentManager().popBackStack();
111                 return true;
112             }
113         }
114         return super.onOptionsItemSelected(item);
115     }
116 
getOtherGroup()117     private PreferenceGroup getOtherGroup() {
118         PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER);
119         if (otherGroup == null) {
120             otherGroup = new PreferenceCategory(getPreferenceManager().getContext());
121             otherGroup.setKey(KEY_OTHER);
122             otherGroup.setTitle(getString(R.string.other_permissions));
123             getPreferenceScreen().addPreference(otherGroup);
124         }
125         return otherGroup;
126     }
127 
updateUi()128     private void updateUi() {
129         getPreferenceScreen().removeAll();
130 
131         ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting.
132         PackageManager pm = getActivity().getPackageManager();
133 
134         ApplicationInfo appInfo = mPackageInfo.applicationInfo;
135         final Drawable icon = appInfo.loadIcon(pm);
136         final CharSequence label = appInfo.loadLabel(pm);
137         Intent infoIntent = null;
138         if (!getActivity().getIntent().getBooleanExtra(
139                 AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) {
140             infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
141                     .setData(Uri.fromParts("package", mPackageInfo.packageName, null));
142         }
143         setHeader(icon, label, infoIntent, null);
144 
145         if (mPackageInfo.requestedPermissions != null) {
146             for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
147                 PermissionInfo perm;
148                 try {
149                     perm = pm.getPermissionInfo(mPackageInfo.requestedPermissions[i], 0);
150                 } catch (NameNotFoundException e) {
151                     Log.e(LOG_TAG, "Can't get permission info for "
152                             + mPackageInfo.requestedPermissions[i], e);
153                     continue;
154                 }
155 
156                 if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
157                         || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
158                     continue;
159                 }
160                 if (appInfo.isInstantApp()
161                         && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0) {
162                     continue;
163                 }
164                 if (appInfo.targetSdkVersion < Build.VERSION_CODES.M
165                         && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
166                         != 0) {
167                     continue;
168                 }
169 
170                 PermissionGroupInfo group = getGroup(Utils.getGroupOfPermission(perm), pm);
171                 if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
172                         == PermissionInfo.PROTECTION_DANGEROUS) {
173                     PreferenceGroup pref = findOrCreate(group != null ? group : perm, pm, prefs);
174                     pref.addPreference(getPreference(perm, group));
175                 } else if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
176                         == PermissionInfo.PROTECTION_NORMAL) {
177                     PreferenceGroup otherGroup = getOtherGroup();
178                     if (prefs.indexOf(otherGroup) < 0) {
179                         prefs.add(otherGroup);
180                     }
181                     getOtherGroup().addPreference(getPreference(perm, group));
182                 }
183             }
184         }
185 
186         // Sort an ArrayList of the groups and then set the order from the sorting.
187         Collections.sort(prefs, new Comparator<Preference>() {
188             @Override
189             public int compare(Preference lhs, Preference rhs) {
190                 String lKey = lhs.getKey();
191                 String rKey = rhs.getKey();
192                 if (lKey.equals(KEY_OTHER)) {
193                     return 1;
194                 } else if (rKey.equals(KEY_OTHER)) {
195                     return -1;
196                 } else if (Utils.isModernPermissionGroup(lKey)
197                         != Utils.isModernPermissionGroup(rKey)) {
198                     return Utils.isModernPermissionGroup(lKey) ? -1 : 1;
199                 }
200                 return lhs.getTitle().toString().compareTo(rhs.getTitle().toString());
201             }
202         });
203         for (int i = 0; i < prefs.size(); i++) {
204             prefs.get(i).setOrder(i);
205         }
206     }
207 
getGroup(String group, PackageManager pm)208     private PermissionGroupInfo getGroup(String group, PackageManager pm) {
209         try {
210             return pm.getPermissionGroupInfo(group, 0);
211         } catch (NameNotFoundException e) {
212             return null;
213         }
214     }
215 
findOrCreate(PackageItemInfo group, PackageManager pm, ArrayList<Preference> prefs)216     private PreferenceGroup findOrCreate(PackageItemInfo group, PackageManager pm,
217             ArrayList<Preference> prefs) {
218         PreferenceGroup pref = (PreferenceGroup) findPreference(group.name);
219         if (pref == null) {
220             pref = new PreferenceCategory(getActivity());
221             pref.setKey(group.name);
222             pref.setLayoutResource(R.layout.preference_category_material);
223             pref.setTitle(group.loadLabel(pm));
224             prefs.add(pref);
225             getPreferenceScreen().addPreference(pref);
226         }
227         return pref;
228     }
229 
getPreference(final PermissionInfo perm, final PermissionGroupInfo group)230     private Preference getPreference(final PermissionInfo perm, final PermissionGroupInfo group) {
231         if (isMutableGranularPermission(perm.name)) {
232             return getMutablePreference(perm, group);
233         } else {
234             return getImmutablePreference(perm, group);
235         }
236     }
237 
getMutablePreference(final PermissionInfo perm, PermissionGroupInfo group)238     private Preference getMutablePreference(final PermissionInfo perm, PermissionGroupInfo group) {
239         final AppPermissionGroup permGroup = mAppPermissions.getPermissionGroup(group.name);
240         final String[] filterPermissions = new String[]{perm.name};
241 
242         // TODO: No hardcoded layouts
243         SwitchPreference pref = new SwitchPreference(getPreferenceManager().getContext());
244         pref.setLayoutResource(R.layout.preference_permissions);
245         pref.setChecked(permGroup.areRuntimePermissionsGranted(filterPermissions));
246         pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group));
247         pref.setTitle(perm.loadLabel(getActivity().getPackageManager()));
248         pref.setPersistent(false);
249 
250         pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
251             @Override
252             public boolean onPreferenceChange(Preference preference, Object value) {
253                 if (value == Boolean.TRUE) {
254                     permGroup.grantRuntimePermissions(false, filterPermissions);
255                 } else {
256                     permGroup.revokeRuntimePermissions(false, filterPermissions);
257                 }
258                 return true;
259             }
260         });
261 
262         return pref;
263     }
264 
getImmutablePreference(final PermissionInfo perm, PermissionGroupInfo group)265     private Preference getImmutablePreference(final PermissionInfo perm,
266             PermissionGroupInfo group) {
267         final PackageManager pm = getActivity().getPackageManager();
268 
269         // TODO: No hardcoded layouts
270         Preference pref = new Preference(getActivity());
271         pref.setLayoutResource(R.layout.preference_permissions);
272         pref.setIcon(getTintedPermissionIcon(getActivity(), perm, group));
273         pref.setTitle(perm.loadLabel(pm));
274         pref.setPersistent(false);
275 
276         pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
277             @Override
278             public boolean onPreferenceClick(Preference preference) {
279                 new AlertDialog.Builder(getActivity())
280                         .setMessage(perm.loadDescription(pm))
281                         .setPositiveButton(android.R.string.ok, null)
282                         .show();
283                 return true;
284             }
285         });
286 
287         return pref;
288     }
289 
getTintedPermissionIcon(Context context, PermissionInfo perm, PermissionGroupInfo group)290     private static Drawable getTintedPermissionIcon(Context context, PermissionInfo perm,
291             PermissionGroupInfo group) {
292         final Drawable icon;
293         if (perm.icon != 0) {
294             icon = perm.loadIcon(context.getPackageManager());
295         } else if (group != null && group.icon != 0) {
296             icon = group.loadIcon(context.getPackageManager());
297         } else {
298             icon =  context.getDrawable(R.drawable.ic_perm_device_info);
299         }
300         return Utils.applyTint(context, icon, android.R.attr.colorControlNormal);
301     }
302 
isMutableGranularPermission(String name)303     private boolean isMutableGranularPermission(String name) {
304         if (!getContext().getPackageManager().arePermissionsIndividuallyControlled()) {
305             return false;
306         }
307         switch (name) {
308             case Manifest.permission.READ_CONTACTS:
309             case Manifest.permission.WRITE_CONTACTS:
310             case Manifest.permission.READ_SMS:
311             case Manifest.permission.READ_CALL_LOG:
312             case Manifest.permission.CALL_PHONE: {
313                 return true;
314             }
315         }
316         return false;
317     }
318 }
319