FileDocCategorySizeDatePackage
AppSecurityPermissions.javaAPI DocAndroid 1.5 API19891Wed May 06 22:41:56 BST 2009android.widget

AppSecurityPermissions

public class AppSecurityPermissions extends Object implements View.OnClickListener
This class contains the SecurityPermissions view implementation. Initially the package's advanced or dangerous security permissions are displayed under categorized groups. Clicking on the additional permissions presents extended information consisting of all groups and permissions. To use this view define a LinearLayout or any ViewGroup and add this view by instantiating AppSecurityPermissions and invoking getPermissionsView. {@hide}

Fields Summary
private static final String
TAG
private boolean
localLOGV
private android.content.Context
mContext
private android.view.LayoutInflater
mInflater
private android.content.pm.PackageManager
mPm
private LinearLayout
mPermsView
private Map
mDangerousMap
private Map
mNormalMap
private List
mPermsList
private String
mDefaultGrpLabel
private String
mDefaultGrpName
private String
mPermFormat
private android.graphics.drawable.Drawable
mNormalIcon
private android.graphics.drawable.Drawable
mDangerousIcon
private boolean
mExpanded
private android.graphics.drawable.Drawable
mShowMaxIcon
private android.graphics.drawable.Drawable
mShowMinIcon
private android.view.View
mShowMore
private TextView
mShowMoreText
private ImageView
mShowMoreIcon
private State
mCurrentState
private LinearLayout
mNonDangerousList
private LinearLayout
mDangerousList
private HashMap
mGroupLabelCache
private android.view.View
mNoPermsView
Constructors Summary
public AppSecurityPermissions(android.content.Context context, List permList)

    
         
        mContext = context;
        mPm = mContext.getPackageManager();
        mPermsList = permList;
    
public AppSecurityPermissions(android.content.Context context, String packageName)

        mContext = context;
        mPm = mContext.getPackageManager();
        mPermsList = new ArrayList<PermissionInfo>();
        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
        PackageInfo pkgInfo;
        try {
            pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
        } catch (NameNotFoundException e) {
            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
            return;
        }
        // Extract all user permissions
        if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) {
            getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet);
        }
        for(PermissionInfo tmpInfo : permSet) {
            mPermsList.add(tmpInfo);
        }
    
public AppSecurityPermissions(android.content.Context context, PackageParser.Package pkg)

        mContext = context;
        mPm = mContext.getPackageManager();
        mPermsList = new ArrayList<PermissionInfo>();
        Set<PermissionInfo> permSet = new HashSet<PermissionInfo>();
        if(pkg == null) {
            return;
        }
        // Extract shared user permissions if any
        if(pkg.mSharedUserId != null) {
            int sharedUid;
            try {
                sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId);
            } catch (NameNotFoundException e) {
                Log.w(TAG, "Could'nt retrieve shared user id for:"+pkg.packageName);
                return;
            }
            getAllUsedPermissions(sharedUid, permSet);
        } else {
            ArrayList<String> strList = pkg.requestedPermissions;
            int size;
            if((strList == null) || ((size = strList.size()) == 0)) {
                return;
            }
            // Extract permissions defined in current package
            extractPerms(strList.toArray(new String[size]), permSet);
        }
        for(PermissionInfo tmpInfo : permSet) {
            mPermsList.add(tmpInfo);
        }
    
Methods Summary
private voidaggregateGroupDescs(java.util.Map map, java.util.Map retMap)

        if(map == null) {
            return;
        }
        if(retMap == null) {
           return;
        }
        Set<String> grpNames = map.keySet();
        Iterator<String> grpNamesIter = grpNames.iterator();
        while(grpNamesIter.hasNext()) {
            String grpDesc = null;
            String grpNameKey = grpNamesIter.next();
            List<PermissionInfo> grpPermsList = map.get(grpNameKey);
            if(grpPermsList == null) {
                continue;
            }
            for(PermissionInfo permInfo: grpPermsList) {
                CharSequence permDesc = permInfo.loadLabel(mPm);
                grpDesc = formatPermissions(grpDesc, permDesc);
            }
            // Insert grpDesc into map
            if(grpDesc != null) {
                if(localLOGV) Log.i(TAG, "Group:"+grpNameKey+" description:"+grpDesc.toString());
                retMap.put(grpNameKey, grpDesc.toString());
            }
        }
    
private java.lang.StringcanonicalizeGroupDesc(java.lang.String groupDesc)
Canonicalizes the group description before it is displayed to the user. TODO check for internationalization issues remove trailing '.' in str1

        if ((groupDesc == null) || (groupDesc.length() == 0)) {
            return null;
        }
        // Both str1 and str2 are non-null and are non-zero in size.
        int len = groupDesc.length();
        if(groupDesc.charAt(len-1) == '.") {
            groupDesc = groupDesc.substring(0, len-1);
        }
        return groupDesc;
    
private voiddisplayNoPermissions()

        mNoPermsView.setVisibility(View.VISIBLE);
    
private voiddisplayPermissions(boolean dangerous)
Utility method that displays permissions from a map containing group name and list of permission descriptions.

        Map<String, String> permInfoMap = dangerous ? mDangerousMap : mNormalMap;
        LinearLayout permListView = dangerous ? mDangerousList : mNonDangerousList;
        permListView.removeAllViews();

        Set<String> permInfoStrSet = permInfoMap.keySet();
        for (String loopPermGrpInfoStr : permInfoStrSet) {
            CharSequence grpLabel = getGroupLabel(loopPermGrpInfoStr);
            //guaranteed that grpLabel wont be null since permissions without groups
            //will belong to the default group
            if(localLOGV) Log.i(TAG, "Adding view group:" + grpLabel + ", desc:"
                    + permInfoMap.get(loopPermGrpInfoStr));
            permListView.addView(getPermissionItemView(grpLabel,
                    permInfoMap.get(loopPermGrpInfoStr), dangerous));
        }
    
private voidextractPerms(java.lang.String[] strList, java.util.Set permSet)

        if((strList == null) || (strList.length == 0)) {
            return;
        }
        for(String permName:strList) {
            try {
                PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0);
                if(tmpPermInfo != null) {
                    permSet.add(tmpPermInfo);
                }
            } catch (NameNotFoundException e) {
                Log.i(TAG, "Ignoring unknown permission:"+permName);
            }
        }
    
private java.lang.StringformatPermissions(java.lang.String groupDesc, java.lang.CharSequence permDesc)
Utility method that concatenates two strings defined by mPermFormat. a null value is returned if both str1 and str2 are null, if one of the strings is null the other non null value is returned without formatting this is to placate initial error checks

        if(groupDesc == null) {
            if(permDesc == null) {
                return null;
            }
            return permDesc.toString();
        }
        groupDesc = canonicalizeGroupDesc(groupDesc);
        if(permDesc == null) {
            return groupDesc;
        }
        // groupDesc and permDesc are non null
        return String.format(mPermFormat, groupDesc, permDesc.toString());
    
private voidgetAllUsedPermissions(int sharedUid, java.util.Set permSet)

        String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
        if(sharedPkgList == null || (sharedPkgList.length == 0)) {
            return;
        }
        for(String sharedPkg : sharedPkgList) {
            getPermissionsForPackage(sharedPkg, permSet);
        }
    
private java.lang.CharSequencegetGroupLabel(java.lang.String grpName)

        if (grpName == null) {
            //return default label
            return mDefaultGrpLabel;
        }
        CharSequence cachedLabel = mGroupLabelCache.get(grpName);
        if (cachedLabel != null) {
            return cachedLabel;
        }
        PermissionGroupInfo pgi;
        try {
            pgi = mPm.getPermissionGroupInfo(grpName, 0);
        } catch (NameNotFoundException e) {
            Log.i(TAG, "Invalid group name:" + grpName);
            return null;
        }
        CharSequence label = pgi.loadLabel(mPm).toString();
        mGroupLabelCache.put(grpName, label);
        return label;
    
public PackageParser.PackagegetPackageInfo(android.net.Uri packageURI)

        final String archiveFilePath = packageURI.getPath();
        PackageParser packageParser = new PackageParser(archiveFilePath);
        File sourceFile = new File(archiveFilePath);
        DisplayMetrics metrics = new DisplayMetrics();
        metrics.setToDefaults();
        return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
    
public intgetPermissionCount()

        return mPermsList.size();
    
private android.view.ViewgetPermissionItemView(java.lang.CharSequence grpName, java.lang.String permList, boolean dangerous)

        View permView = mInflater.inflate(R.layout.app_permission_item, null);
        Drawable icon = dangerous ? mDangerousIcon : mNormalIcon;
        int grpColor = dangerous ? R.color.perms_dangerous_grp_color :
            R.color.perms_normal_grp_color;
        int permColor = dangerous ? R.color.perms_dangerous_perm_color :
            R.color.perms_normal_perm_color;

        TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
        TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
        permGrpView.setTextColor(mContext.getResources().getColor(grpColor));
        permDescView.setTextColor(mContext.getResources().getColor(permColor));

        ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
        imgView.setImageDrawable(icon);
        if(grpName != null) {
            permGrpView.setText(grpName);
            permDescView.setText(permList);
        } else {
            permGrpView.setText(permList);
            permDescView.setVisibility(View.GONE);
        }
        return permView;
    
private voidgetPermissionsForPackage(java.lang.String packageName, java.util.Set permSet)

        PackageInfo pkgInfo;
        try {
            pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
        } catch (NameNotFoundException e) {
            Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName);
            return;
        }
        if(pkgInfo == null) {
            return;
        }
        String strList[] = pkgInfo.requestedPermissions;
        if(strList == null) {
            return;
        }
        extractPerms(strList, permSet);
    
public android.view.ViewgetPermissionsView()

        
        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mPermsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
        mShowMore = mPermsView.findViewById(R.id.show_more);
        mShowMoreIcon = (ImageView) mShowMore.findViewById(R.id.show_more_icon);
        mShowMoreText = (TextView) mShowMore.findViewById(R.id.show_more_text);
        mDangerousList = (LinearLayout) mPermsView.findViewById(R.id.dangerous_perms_list);
        mNonDangerousList = (LinearLayout) mPermsView.findViewById(R.id.non_dangerous_perms_list);
        mNoPermsView = mPermsView.findViewById(R.id.no_permissions);

        // Set up the LinearLayout that acts like a list item.
        mShowMore.setClickable(true);
        mShowMore.setOnClickListener(this);
        mShowMore.setFocusable(true);
        mShowMore.setBackgroundResource(android.R.drawable.list_selector_background);

        // Pick up from framework resources instead.
        mDefaultGrpLabel = mContext.getString(R.string.default_permission_group);
        mPermFormat = mContext.getString(R.string.permissions_format);
        mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot);
        mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission);
        mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_maximized);
        mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_ic_minimized);
        
        // Set permissions view
        setPermissions(mPermsList);
        return mPermsView;
    
private booleanisDisplayablePermission(android.content.pm.PermissionInfo pInfo)

        if(pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS ||
                pInfo.protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
            return true;
        }
        return false;
    
public voidonClick(android.view.View v)

        if(localLOGV) Log.i(TAG, "mExpanded="+mExpanded);
        mExpanded = !mExpanded;
        showPermissions();
    
private voidsetPermissions(java.util.List permList)

        mGroupLabelCache = new HashMap<String, CharSequence>();
        //add the default label so that uncategorized permissions can go here
        mGroupLabelCache.put(mDefaultGrpName, mDefaultGrpLabel);
        
        // Map containing group names and a list of permissions under that group
        // categorized as dangerous
        mDangerousMap = new HashMap<String, String>();
        // Map containing group names and a list of permissions under that group
        // categorized as normal
        mNormalMap = new HashMap<String, String>();
        
        // Additional structures needed to ensure that permissions are unique under 
        // each group
        Map<String, List<PermissionInfo>> dangerousMap = 
            new HashMap<String,  List<PermissionInfo>>();
        Map<String, List<PermissionInfo> > normalMap = 
            new HashMap<String,  List<PermissionInfo>>();
        PermissionInfoComparator permComparator = new PermissionInfoComparator(mPm);
        
        if (permList != null) {
            // First pass to group permissions
            for (PermissionInfo pInfo : permList) {
                if(localLOGV) Log.i(TAG, "Processing permission:"+pInfo.name);
                if(!isDisplayablePermission(pInfo)) {
                    if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" is not displayable");
                    continue;
                }
                Map<String, List<PermissionInfo> > permInfoMap =
                    (pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) ?
                            dangerousMap : normalMap;
                String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group;
                if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" belongs to group:"+grpName);
                List<PermissionInfo> grpPermsList = permInfoMap.get(grpName);
                if(grpPermsList == null) {
                    grpPermsList = new ArrayList<PermissionInfo>();
                    permInfoMap.put(grpName, grpPermsList);
                    grpPermsList.add(pInfo);
                } else {
                    int idx = Collections.binarySearch(grpPermsList, pInfo, permComparator);
                    if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+grpPermsList.size());
                    if (idx < 0) {
                        idx = -idx-1;
                        grpPermsList.add(idx, pInfo);
                    }
                }
            }
            // Second pass to actually form the descriptions
            // Look at dangerous permissions first
            aggregateGroupDescs(dangerousMap, mDangerousMap);
            aggregateGroupDescs(normalMap, mNormalMap);
        }

        mCurrentState = State.NO_PERMS;
        if(mDangerousMap.size() > 0) {
            mCurrentState = (mNormalMap.size() > 0) ? State.BOTH : State.DANGEROUS_ONLY;
        } else if(mNormalMap.size() > 0) {
            mCurrentState = State.NORMAL_ONLY;
        }
        if(localLOGV) Log.i(TAG, "mCurrentState=" + mCurrentState);
        showPermissions();
    
private voidshowPermissions()


        switch(mCurrentState) {
        case NO_PERMS:
            displayNoPermissions();
            break;

        case DANGEROUS_ONLY:
            displayPermissions(true);
            break;

        case NORMAL_ONLY:
            displayPermissions(false);
            break;

        case BOTH:
            displayPermissions(true);
            if (mExpanded) {
                displayPermissions(false);
                mShowMoreIcon.setImageDrawable(mShowMaxIcon);
                mShowMoreText.setText(R.string.perms_hide);
                mNonDangerousList.setVisibility(View.VISIBLE);
            } else {
                mShowMoreIcon.setImageDrawable(mShowMinIcon);
                mShowMoreText.setText(R.string.perms_show_all);
                mNonDangerousList.setVisibility(View.GONE);
            }
            mShowMore.setVisibility(View.VISIBLE);
            break;
        }