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.content.Context; 20 import android.content.pm.PackageInfo; 21 import android.content.pm.PackageManager; 22 import android.text.BidiFormatter; 23 import android.text.TextPaint; 24 import android.text.TextUtils; 25 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.LinkedHashMap; 29 import java.util.List; 30 31 public final class AppPermissions { 32 private static final float MAX_APP_LABEL_LENGTH_PIXELS = 500; 33 34 private static final TextPaint sAppLabelEllipsizePaint = new TextPaint(); 35 static { 36 sAppLabelEllipsizePaint.setAntiAlias(true); 37 // Both text size and width are given in absolute pixels, for consistent truncation 38 // across devices; this value corresponds to the default 14dip size on an xdhpi device. 39 sAppLabelEllipsizePaint.setTextSize(42); 40 } 41 42 private final ArrayList<AppPermissionGroup> mGroups = new ArrayList<>(); 43 44 private final LinkedHashMap<String, AppPermissionGroup> mNameToGroupMap = new LinkedHashMap<>(); 45 46 private final Context mContext; 47 48 private final String[] mFilterPermissions; 49 50 private final CharSequence mAppLabel; 51 52 private final Runnable mOnErrorCallback; 53 54 private final boolean mSortGroups; 55 56 private PackageInfo mPackageInfo; 57 58 public AppPermissions(Context context, PackageInfo packageInfo, String[] permissions, 59 boolean sortGroups, Runnable onErrorCallback) { 60 mContext = context; 61 mPackageInfo = packageInfo; 62 mFilterPermissions = permissions; 63 mAppLabel = loadEllipsizedAppLabel(context, packageInfo); 64 mSortGroups = sortGroups; 65 mOnErrorCallback = onErrorCallback; 66 loadPermissionGroups(); 67 } 68 69 public PackageInfo getPackageInfo() { 70 return mPackageInfo; 71 } 72 73 public void refresh() { 74 loadPackageInfo(); 75 loadPermissionGroups(); 76 } 77 78 public CharSequence getAppLabel() { 79 return mAppLabel; 80 } 81 82 public AppPermissionGroup getPermissionGroup(String name) { 83 return mNameToGroupMap.get(name); 84 } 85 86 public List<AppPermissionGroup> getPermissionGroups() { 87 return mGroups; 88 } 89 90 91 private void loadPackageInfo() { 92 try { 93 mPackageInfo = mContext.getPackageManager().getPackageInfo( 94 mPackageInfo.packageName, PackageManager.GET_PERMISSIONS); 95 } catch (PackageManager.NameNotFoundException e) { 96 if (mOnErrorCallback != null) { 97 mOnErrorCallback.run(); 98 } 99 } 100 } 101 102 private void loadPermissionGroups() { 103 mGroups.clear(); 104 105 if (mPackageInfo.requestedPermissions == null) { 106 return; 107 } 108 109 if (mFilterPermissions != null) { 110 for (String filterPermission : mFilterPermissions) { 111 for (String requestedPerm : mPackageInfo.requestedPermissions) { 112 if (!filterPermission.equals(requestedPerm)) { 113 continue; 114 } 115 116 if (hasGroupForPermission(requestedPerm)) { 117 break; 118 } 119 120 AppPermissionGroup group = AppPermissionGroup.create(mContext, 121 mPackageInfo, requestedPerm); 122 if (group == null) { 123 break; 124 } 125 126 mGroups.add(group); 127 break; 128 } 129 } 130 } else { 131 for (String requestedPerm : mPackageInfo.requestedPermissions) { 132 if (hasGroupForPermission(requestedPerm)) { 133 continue; 134 } 135 136 AppPermissionGroup group = AppPermissionGroup.create(mContext, 137 mPackageInfo, requestedPerm); 138 if (group == null) { 139 continue; 140 } 141 142 mGroups.add(group); 143 } 144 } 145 146 if (mSortGroups) { 147 Collections.sort(mGroups); 148 } 149 150 mNameToGroupMap.clear(); 151 for (AppPermissionGroup group : mGroups) { 152 mNameToGroupMap.put(group.getName(), group); 153 } 154 } 155 156 private boolean hasGroupForPermission(String permission) { 157 for (AppPermissionGroup group : mGroups) { 158 if (group.hasPermission(permission)) { 159 return true; 160 } 161 } 162 return false; 163 } 164 165 private static CharSequence loadEllipsizedAppLabel(Context context, PackageInfo packageInfo) { 166 String label = packageInfo.applicationInfo.loadLabel( 167 context.getPackageManager()).toString(); 168 String noNewLineLabel = label.replace("\n", " "); 169 String ellipsizedLabel = TextUtils.ellipsize(noNewLineLabel, sAppLabelEllipsizePaint, 170 MAX_APP_LABEL_LENGTH_PIXELS, TextUtils.TruncateAt.END).toString(); 171 return BidiFormatter.getInstance().unicodeWrap(ellipsizedLabel); 172 } 173 } 174