Home | History | Annotate | Download | only in television
      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 
     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
     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
    100     public void onResume() {
    101         super.onResume();
    102         updateUi();
    103     }
    104 
    105     @Override
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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