• 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.support.v14.preference.SwitchPreference;
37 import android.support.v7.preference.Preference;
38 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
39 import android.support.v7.preference.Preference.OnPreferenceClickListener;
40 import android.support.v7.preference.PreferenceCategory;
41 import android.support.v7.preference.PreferenceGroup;
42 import android.util.Log;
43 import android.view.MenuItem;
44 
45 import com.android.packageinstaller.R;
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 
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.Comparator;
53 
54 public final class AllAppPermissionsFragment extends SettingsWithHeader {
55 
56     private static final String LOG_TAG = "AllAppPermissionsFragment";
57 
58     private static final String KEY_OTHER = "other_perms";
59 
60     private PackageInfo mPackageInfo;
61 
62     private AppPermissions mAppPermissions;
63 
newInstance(String packageName)64     public static AllAppPermissionsFragment newInstance(String packageName) {
65         AllAppPermissionsFragment instance = new AllAppPermissionsFragment();
66         Bundle arguments = new Bundle();
67         arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
68         instance.setArguments(arguments);
69         return instance;
70     }
71 
72     @Override
onCreate(Bundle savedInstanceState)73     public void onCreate(Bundle savedInstanceState) {
74         super.onCreate(savedInstanceState);
75         setHasOptionsMenu(true);
76         final ActionBar ab = getActivity().getActionBar();
77         if (ab != null) {
78             ab.setTitle(R.string.all_permissions);
79             ab.setDisplayHomeAsUpEnabled(true);
80         }
81 
82         String pkg = getArguments().getString(Intent.EXTRA_PACKAGE_NAME);
83         try {
84             mPackageInfo = getActivity().getPackageManager().getPackageInfo(pkg,
85                     PackageManager.GET_PERMISSIONS);
86         } catch (NameNotFoundException e) {
87             getActivity().finish();
88         }
89 
90         mAppPermissions = new AppPermissions(getActivity(), mPackageInfo, null, false,
91                 new Runnable() {
92             @Override
93             public void run() {
94                 getActivity().finish();
95             }
96         });
97     }
98 
99     @Override
onResume()100     public void onResume() {
101         super.onResume();
102         updateUi();
103     }
104 
105     @Override
onOptionsItemSelected(MenuItem item)106     public boolean onOptionsItemSelected(MenuItem item) {
107         switch (item.getItemId()) {
108             case android.R.id.home: {
109                 getFragmentManager().popBackStack();
110                 return true;
111             }
112         }
113         return super.onOptionsItemSelected(item);
114     }
115 
getOtherGroup()116     private PreferenceGroup getOtherGroup() {
117         PreferenceGroup otherGroup = (PreferenceGroup) findPreference(KEY_OTHER);
118         if (otherGroup == null) {
119             otherGroup = new PreferenceCategory(getPreferenceManager().getContext());
120             otherGroup.setKey(KEY_OTHER);
121             otherGroup.setTitle(getString(R.string.other_permissions));
122             getPreferenceScreen().addPreference(otherGroup);
123         }
124         return otherGroup;
125     }
126 
updateUi()127     private void updateUi() {
128         getPreferenceScreen().removeAll();
129 
130         ArrayList<Preference> prefs = new ArrayList<>(); // Used for sorting.
131         PackageManager pm = getActivity().getPackageManager();
132 
133         ApplicationInfo appInfo = mPackageInfo.applicationInfo;
134         final Drawable icon = appInfo.loadIcon(pm);
135         final CharSequence label = appInfo.loadLabel(pm);
136         Intent infoIntent = null;
137         if (!getActivity().getIntent().getBooleanExtra(
138                 AppPermissionsFragment.EXTRA_HIDE_INFO_BUTTON, false)) {
139             infoIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
140                     .setData(Uri.fromParts("package", mPackageInfo.packageName, null));
141         }
142         setHeader(icon, label, infoIntent, null);
143 
144         if (mPackageInfo.requestedPermissions != null) {
145             for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
146                 PermissionInfo perm;
147                 try {
148                     perm = pm.getPermissionInfo(mPackageInfo.requestedPermissions[i], 0);
149                 } catch (NameNotFoundException e) {
150                     Log.e(LOG_TAG, "Can't get permission info for "
151                             + mPackageInfo.requestedPermissions[i], e);
152                     continue;
153                 }
154 
155                 if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
156                         || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
157                     continue;
158                 }
159                 if (appInfo.isInstantApp()
160                         && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) == 0) {
161                     continue;
162                 }
163                 if (appInfo.targetSdkVersion < Build.VERSION_CODES.M
164                         && (perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
165                         != 0) {
166                     continue;
167                 }
168 
169 
170                 PermissionGroupInfo group = getGroup(perm.group, 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().isPermissionReviewModeEnabled()) {
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