Home | History | Annotate | Download | only in model
      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.model;
     18 
     19 import android.app.LoaderManager;
     20 import android.app.LoaderManager.LoaderCallbacks;
     21 import android.content.AsyncTaskLoader;
     22 import android.content.Context;
     23 import android.content.Loader;
     24 import android.content.pm.PackageInfo;
     25 import android.content.pm.PackageItemInfo;
     26 import android.content.pm.PackageManager;
     27 import android.content.pm.PermissionGroupInfo;
     28 import android.content.pm.PermissionInfo;
     29 import android.graphics.drawable.Drawable;
     30 import android.os.Bundle;
     31 import android.util.ArraySet;
     32 
     33 import com.android.packageinstaller.R;
     34 import com.android.packageinstaller.permission.utils.Utils;
     35 
     36 import java.util.ArrayList;
     37 import java.util.Collections;
     38 import java.util.List;
     39 import java.util.Set;
     40 
     41 public final class PermissionGroups implements LoaderCallbacks<List<PermissionGroup>> {
     42     private final ArrayList<PermissionGroup> mGroups = new ArrayList<>();
     43     private final Context mContext;
     44     private final LoaderManager mLoaderManager;
     45     private final PermissionsGroupsChangeCallback mCallback;
     46 
     47     public interface PermissionsGroupsChangeCallback {
     48         public void onPermissionGroupsChanged();
     49     }
     50 
     51     public PermissionGroups(Context context, LoaderManager loaderManager,
     52             PermissionsGroupsChangeCallback callback) {
     53         mContext = context;
     54         mLoaderManager = loaderManager;
     55         mCallback = callback;
     56     }
     57 
     58     @Override
     59     public Loader<List<PermissionGroup>> onCreateLoader(int id, Bundle args) {
     60         return new PermissionsLoader(mContext);
     61     }
     62 
     63     @Override
     64     public void onLoadFinished(Loader<List<PermissionGroup>> loader,
     65             List<PermissionGroup> groups) {
     66         if (mGroups.equals(groups)) {
     67             return;
     68         }
     69         mGroups.clear();
     70         mGroups.addAll(groups);
     71         mCallback.onPermissionGroupsChanged();
     72     }
     73 
     74     @Override
     75     public void onLoaderReset(Loader<List<PermissionGroup>> loader) {
     76         mGroups.clear();
     77         mCallback.onPermissionGroupsChanged();
     78     }
     79 
     80     public void refresh() {
     81         mLoaderManager.restartLoader(0, null, this);
     82         mLoaderManager.getLoader(0).forceLoad();
     83     }
     84 
     85     public List<PermissionGroup> getGroups() {
     86         return mGroups;
     87     }
     88 
     89     public PermissionGroup getGroup(String name) {
     90         for (PermissionGroup group : mGroups) {
     91             if (group.getName().equals(name)) {
     92                 return group;
     93             }
     94         }
     95         return null;
     96     }
     97 
     98     private static final class PermissionsLoader extends AsyncTaskLoader<List<PermissionGroup>> {
     99 
    100         public PermissionsLoader(Context context) {
    101             super(context);
    102         }
    103 
    104         @Override
    105         public List<PermissionGroup> loadInBackground() {
    106             List<PermissionGroup> groups = new ArrayList<>();
    107             Set<String> seenPermissions = new ArraySet<>();
    108 
    109 
    110             PackageManager packageManager = getContext().getPackageManager();
    111             List<PermissionGroupInfo> groupInfos = packageManager.getAllPermissionGroups(0);
    112 
    113             for (PermissionGroupInfo groupInfo : groupInfos) {
    114                 // Mare sure we respond to cancellation.
    115                 if (isLoadInBackgroundCanceled()) {
    116                     return Collections.emptyList();
    117                 }
    118 
    119                 // Get the permissions in this group.
    120                 final List<PermissionInfo> groupPermissions;
    121                 try {
    122                     groupPermissions = packageManager.queryPermissionsByGroup(groupInfo.name, 0);
    123                 } catch (PackageManager.NameNotFoundException e) {
    124                     continue;
    125                 }
    126 
    127                 boolean hasRuntimePermissions = false;
    128 
    129                 // Cache seen permissions and see if group has runtime permissions.
    130                 for (PermissionInfo groupPermission : groupPermissions) {
    131                     seenPermissions.add(groupPermission.name);
    132                     if (groupPermission.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS
    133                             && (groupPermission.flags & PermissionInfo.FLAG_INSTALLED) != 0
    134                             && (groupPermission.flags & PermissionInfo.FLAG_HIDDEN) == 0) {
    135                         hasRuntimePermissions = true;
    136                     }
    137                 }
    138 
    139                 // No runtime permissions - not interesting for us.
    140                 if (!hasRuntimePermissions) {
    141                     continue;
    142                 }
    143 
    144                 CharSequence label = loadItemInfoLabel(groupInfo);
    145                 Drawable icon = loadItemInfoIcon(groupInfo);
    146 
    147                 // Create the group and add to the list.
    148                 PermissionGroup group = new PermissionGroup(groupInfo.name,
    149                         groupInfo.packageName, label, icon);
    150                 groups.add(group);
    151             }
    152 
    153 
    154             // Make sure we add groups for lone runtime permissions.
    155             List<PackageInfo> installedPackages = getContext().getPackageManager()
    156                     .getInstalledPackages(PackageManager.GET_PERMISSIONS);
    157 
    158 
    159             // We will filter out permissions that no package requests.
    160             Set<String> requestedPermissions = new ArraySet<>();
    161             for (PackageInfo installedPackage : installedPackages) {
    162                 if (installedPackage.requestedPermissions == null) {
    163                     continue;
    164                 }
    165                 for (String requestedPermission : installedPackage.requestedPermissions) {
    166                     requestedPermissions.add(requestedPermission);
    167                 }
    168             }
    169 
    170             for (PackageInfo installedPackage : installedPackages) {
    171                 if (installedPackage.permissions == null) {
    172                     continue;
    173                 }
    174 
    175                 for (PermissionInfo permissionInfo : installedPackage.permissions) {
    176                     // If we have handled this permission, no more work to do.
    177                     if (!seenPermissions.add(permissionInfo.name)) {
    178                         continue;
    179                     }
    180 
    181                     // We care only about installed runtime permissions.
    182                     if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS
    183                             || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0) {
    184                         continue;
    185                     }
    186 
    187                     // If no app uses this permission,
    188                     if (!requestedPermissions.contains(permissionInfo.name)) {
    189                         continue;
    190                     }
    191 
    192                     CharSequence label = loadItemInfoLabel(permissionInfo);
    193                     Drawable icon = loadItemInfoIcon(permissionInfo);
    194 
    195                     // Create the group and add to the list.
    196                     PermissionGroup group = new PermissionGroup(permissionInfo.name,
    197                             permissionInfo.packageName, label, icon);
    198                     groups.add(group);
    199                 }
    200             }
    201 
    202             Collections.sort(groups);
    203             return groups;
    204         }
    205 
    206         private CharSequence loadItemInfoLabel(PackageItemInfo itemInfo) {
    207             CharSequence label = itemInfo.loadLabel(getContext().getPackageManager());
    208             if (label == null) {
    209                 label = itemInfo.name;
    210             }
    211             return label;
    212         }
    213 
    214         private Drawable loadItemInfoIcon(PackageItemInfo itemInfo) {
    215             final Drawable icon;
    216             if (itemInfo.icon > 0) {
    217                 icon = Utils.loadDrawable(getContext().getPackageManager(),
    218                         itemInfo.packageName, itemInfo.icon);
    219             } else {
    220                 icon = getContext().getDrawable(R.drawable.ic_perm_device_info);
    221             }
    222             return icon;
    223         }
    224     }
    225 }
    226