com.github.michalbednarski.intentslab.PermissionInfoFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.github.michalbednarski.intentslab.PermissionInfoFragment.java

Source

/*
 * IntentsLab - Android app for playing with Intents and Binder IPC
 * Copyright (C) 2014 Micha Bednarski
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.github.michalbednarski.intentslab;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.github.michalbednarski.intentslab.browser.ComponentInfoFragment;
import com.github.michalbednarski.intentslab.providerlab.ProviderInfoFragment;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by mb on 14.07.13.
 */
public class PermissionInfoFragment extends ListFragment {
    public static final String ARG_PERMISSION_NAME = "PermissionInfo.NAME";

    private PackageManager mPm;

    private CharSequence mDetailsText;
    private PackageInfo mDefinedBy;

    private boolean mAppListsReady = false;
    private PackageInfo[] mGrantedTo;
    private PackageInfo[] mImplicitlyGrantedTo;
    private PackageInfo[] mDeniedTo;
    private ComponentInfo[] mEnforcingComponents;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setRetainInstance(true);

        // Get system services
        mPm = getActivity().getApplicationContext().getPackageManager();

        final String permissionName = getArguments().getString(ARG_PERMISSION_NAME);

        // Get information about permission itself
        FormattedTextBuilder headerText = new FormattedTextBuilder();
        headerText.appendGlobalHeader(permissionName);
        try {
            final PermissionInfo permissionInfo = mPm.getPermissionInfo(permissionName, 0);

            headerText.appendGlobalHeader(String.valueOf(permissionInfo.loadLabel(mPm)));
            headerText.appendValue(getString(R.string.description),
                    String.valueOf(permissionInfo.loadDescription(mPm)));

            try {
                if (permissionInfo.group != null) {
                    headerText.appendValue(getString(R.string.permission_group_name), permissionInfo.group);
                    final PermissionGroupInfo permissionGroupInfo = mPm.getPermissionGroupInfo(permissionInfo.group,
                            0);
                    headerText.appendValueNoNewLine(getString(R.string.permission_group_label),
                            String.valueOf(permissionGroupInfo.loadLabel(mPm)));
                    headerText.appendValueNoNewLine(getString(R.string.permission_group_description),
                            String.valueOf(permissionGroupInfo.loadDescription(mPm)));
                }
            } catch (PackageManager.NameNotFoundException ignored) {
            }

            headerText.appendValue(getString(R.string.permission_protection_level),
                    protectionLevelToString(permissionInfo.protectionLevel));
            mDefinedBy = mPm.getPackageInfo(permissionInfo.packageName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            // Undeclared permission
            e.printStackTrace();
        }

        mDetailsText = headerText.getText();

        (new ScanUsingAppsTask()).execute(permissionName);
    }

    class ScanUsingAppsTask extends AsyncTask<String, Object, Object> {
        @Override
        protected Object doInBackground(String... params) {
            String permissionName = params[0];

            // Lists of packages
            ArrayList<PackageInfo> packagesGrantedPermission = new ArrayList<PackageInfo>();
            ArrayList<PackageInfo> packagesDeniedPermission = new ArrayList<PackageInfo>();
            ArrayList<PackageInfo> packagesImplicitlyGrantedPermission = new ArrayList<PackageInfo>();
            ArrayList<ComponentInfo> enforcingComponents = new ArrayList<ComponentInfo>();

            // Scan packages
            List<PackageInfo> installedPackages = mPm.getInstalledPackages(
                    PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
                            | PackageManager.GET_PROVIDERS | PackageManager.GET_PERMISSIONS);
            boolean workAroundSmallBinderBuffer = false;
            if (installedPackages.size() == 0) {
                installedPackages = mPm.getInstalledPackages(0);
                workAroundSmallBinderBuffer = true;
            }

            for (PackageInfo packageInfo : installedPackages) {
                if (workAroundSmallBinderBuffer) {
                    try {
                        packageInfo = mPm.getPackageInfo(packageInfo.packageName,
                                PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
                                        | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS
                                        | PackageManager.GET_PERMISSIONS);
                    } catch (PackageManager.NameNotFoundException e) {
                        // Shouldn't happen (package removed in meantime?)
                        e.printStackTrace();
                        continue;
                    }
                }

                // Find components enforcing this permission
                if (packageInfo.activities != null) {
                    for (ActivityInfo activityInfo : packageInfo.activities) {
                        if (permissionName.equals(activityInfo.permission)) {
                            enforcingComponents.add(activityInfo);
                        }
                    }
                }

                if (packageInfo.receivers != null) {
                    for (ActivityInfo receiverInfo : packageInfo.receivers) {
                        if (permissionName.equals(receiverInfo.permission)) {
                            enforcingComponents.add(receiverInfo);
                        }
                    }
                }

                if (packageInfo.services != null) {
                    for (ServiceInfo serviceInfo : packageInfo.services) {
                        if (permissionName.equals(serviceInfo.permission)) {
                            enforcingComponents.add(serviceInfo);
                        }
                    }
                }

                if (packageInfo.providers != null) {
                    for (ProviderInfo providerInfo : packageInfo.providers) {
                        if (permissionName.equals(providerInfo.readPermission)
                                || permissionName.equals(providerInfo.writePermission)) {
                            enforcingComponents.add(providerInfo);
                        }
                    }
                }

                // Check if app requested/has permission
                if (packageInfo.requestedPermissions != null
                        && Arrays.asList(packageInfo.requestedPermissions).contains(permissionName)) {
                    if (isPermissionGrantedTo(permissionName, packageInfo)) {
                        packagesGrantedPermission.add(packageInfo);
                    } else {
                        packagesDeniedPermission.add(packageInfo);
                    }
                    continue;
                }
                if (isPermissionGrantedTo(permissionName, packageInfo)) {
                    packagesImplicitlyGrantedPermission.add(packageInfo);
                }
            }

            // Prepare ListView displaying all these lists
            mGrantedTo = packagesGrantedPermission.toArray(new PackageInfo[packagesGrantedPermission.size()]);
            mImplicitlyGrantedTo = packagesImplicitlyGrantedPermission
                    .toArray(new PackageInfo[packagesImplicitlyGrantedPermission.size()]);
            mDeniedTo = packagesDeniedPermission.toArray(new PackageInfo[packagesDeniedPermission.size()]);
            mEnforcingComponents = enforcingComponents.toArray(new ComponentInfo[enforcingComponents.size()]);
            return null;
        }

        @Override
        protected void onPostExecute(Object o) {
            mAppListsReady = true;
            mListAdapter.notifyDataSetChanged();
        }
    }

    private boolean isPermissionGrantedTo(String permissionName, PackageInfo packageInfo) {
        return mPm.checkPermission(permissionName, packageInfo.packageName) == PackageManager.PERMISSION_GRANTED;
    }

    @SuppressLint("InlinedApi")
    private static String protectionLevelToString(int protectionLevel) {
        int base = protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
        int flags = protectionLevel & PermissionInfo.PROTECTION_MASK_FLAGS;

        // Base
        StringBuilder builder = new StringBuilder(base == PermissionInfo.PROTECTION_NORMAL ? "normal"
                : base == PermissionInfo.PROTECTION_DANGEROUS ? "dangerous"
                        : base == PermissionInfo.PROTECTION_SIGNATURE ? "signature"
                                : base == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM ? "signatureOrSystem"
                                        : String.valueOf(base) // If none matched
        );

        // Flags
        if ((flags & PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
            builder.append("|system");
        }
        if ((flags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
            builder.append("|development");
        }

        // Unrecognized flags
        int unknownFlags = flags
                & ~(PermissionInfo.PROTECTION_FLAG_SYSTEM | PermissionInfo.PROTECTION_FLAG_DEVELOPMENT);
        if (unknownFlags != 0) {
            builder.append("|");
            builder.append(unknownFlags);
        }
        return builder.toString();
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setListShownNoAnimation(true);
        setListAdapter(mListAdapter);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        Object item = mListAdapter.getItem(position);
        if (item instanceof ComponentInfo) {
            // Component, jump to component info
            ComponentInfo componentInfo = (ComponentInfo) item;
            Intent intent = new Intent(getActivity(), SingleFragmentActivity.class);
            if (componentInfo instanceof ProviderInfo) {
                intent.putExtra(SingleFragmentActivity.EXTRA_FRAGMENT, ProviderInfoFragment.class.getName());
            } else {
                intent.putExtra(SingleFragmentActivity.EXTRA_FRAGMENT, ComponentInfoFragment.class.getName());
            }
            startActivity(intent.putExtra(ComponentInfoFragment.ARG_PACKAGE_NAME, componentInfo.packageName)
                    .putExtra(ComponentInfoFragment.ARG_COMPONENT_NAME, componentInfo.name));
        } else {
            // Package, show our package info
            String packageName = ((PackageInfo) item).packageName;
            startActivity(new Intent(getActivity(), AppInfoActivity.class)
                    .putExtra(AppInfoActivity.EXTRA_PACKAGE_NAME, packageName));
        }
    }

    private final int CATEGORY_DEFINED_BY = 0;
    private final int CATEGORY_LOADING_INDICATOR = 1;
    private final int CATEGORY_GRANTED_TO = 2;
    private final int CATEGORY_IMPLICITLY_GRANTED_TO = 3;
    private final int CATEGORY_DENIED_TO = 4;
    private final int CATEGORY_ENFORCED_BY = 5;

    private CategorizedAdapter mListAdapter = new CategorizedAdapter() {
        @Override
        protected int getCategoryCount() {
            return 6;
        }

        @Override
        protected int getCountInCategory(int category) {
            switch (category) {
            case -1:
                return 1;
            case CATEGORY_DEFINED_BY:
                return mDefinedBy != null ? 1 : 0;
            case CATEGORY_LOADING_INDICATOR:
                return mAppListsReady ? 0 : 1;
            case CATEGORY_GRANTED_TO:
                return mAppListsReady ? mGrantedTo.length : 0;
            case CATEGORY_IMPLICITLY_GRANTED_TO:
                return mAppListsReady ? mImplicitlyGrantedTo.length : 0;
            case CATEGORY_DENIED_TO:
                return mAppListsReady ? mDeniedTo.length : 0;
            case CATEGORY_ENFORCED_BY:
                return mAppListsReady ? mEnforcingComponents.length : 0;
            }
            return 0;
        }

        @Override
        protected String getCategoryName(int category) {
            return getString(category == CATEGORY_DEFINED_BY ? R.string.permission_defined_by
                    : category == CATEGORY_LOADING_INDICATOR ? R.string.loading
                            : category == CATEGORY_GRANTED_TO ? R.string.permission_granted_to
                                    : category == CATEGORY_IMPLICITLY_GRANTED_TO
                                            ? R.string.permission_implicitly_granted_to
                                            : category == CATEGORY_DENIED_TO ? R.string.permission_denied_to
                                                    : category == CATEGORY_ENFORCED_BY
                                                            ? R.string.permission_enforcing_components
                                                            : 0);
        }

        @Override
        protected int getViewTypeInCategory(int category, int positionInCategory) {
            return category == -1 ? 2 : category == CATEGORY_LOADING_INDICATOR ? 3 : 1;
        }

        @Override
        protected View getViewInCategory(int category, int positionInCategory, View convertView, ViewGroup parent) {
            switch (category) {
            case -1:
                if (convertView == null) {
                    TextView detailsTextView = new TextView(parent.getContext());
                    detailsTextView.setText(mDetailsText);
                    return detailsTextView;
                } else {
                    return convertView;
                }
            case CATEGORY_LOADING_INDICATOR:
                if (convertView == null) {
                    return LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_loading2, parent,
                            false);
                } else {
                    return convertView;
                }
            case CATEGORY_DEFINED_BY:
                return createItemViewForPackage(convertView, parent, mDefinedBy);
            case CATEGORY_GRANTED_TO:
                return createItemViewForPackage(convertView, parent, mGrantedTo[positionInCategory]);
            case CATEGORY_IMPLICITLY_GRANTED_TO:
                return createItemViewForPackage(convertView, parent, mImplicitlyGrantedTo[positionInCategory]);
            case CATEGORY_DENIED_TO:
                return createItemViewForPackage(convertView, parent, mDeniedTo[positionInCategory]);
            case CATEGORY_ENFORCED_BY:
                return createItemViewForComponent(convertView, parent, mEnforcingComponents[positionInCategory]);
            }
            return null;
        }

        @Override
        protected boolean isItemInCategoryEnabled(int category, int positionInCategory) {
            return category != -1 && category != CATEGORY_LOADING_INDICATOR;
        }

        private View createItemView(View convertView, ViewGroup parent, String title, String subtitle,
                Drawable icon) {
            if (convertView == null) {
                convertView = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.simple_list_item_2_with_icon, parent, false);
            }

            ((TextView) convertView.findViewById(android.R.id.text1)).setText(title);
            ((TextView) convertView.findViewById(android.R.id.text2)).setText(subtitle);
            ((ImageView) convertView.findViewById(R.id.app_icon)).setImageDrawable(icon);
            return convertView;
        }

        private View createItemViewForPackage(View convertView, ViewGroup parent, PackageInfo packageInfo) {
            return createItemView(convertView, parent, String.valueOf(packageInfo.applicationInfo.loadLabel(mPm)),
                    packageInfo.packageName, packageInfo.applicationInfo.loadIcon(mPm));
        }

        private View createItemViewForComponent(View convertView, ViewGroup parent, ComponentInfo componentInfo) {
            return createItemView(convertView, parent, String.valueOf(componentInfo.loadLabel(mPm)),
                    new ComponentName(componentInfo.packageName, componentInfo.name).flattenToShortString(),
                    componentInfo.loadIcon(mPm));
        }

        @Override
        protected Object getItemInCategory(int category, int positionInCategory) {
            switch (category) {
            case CATEGORY_DEFINED_BY:
                return mDefinedBy;
            case CATEGORY_GRANTED_TO:
                return mGrantedTo[positionInCategory];
            case CATEGORY_IMPLICITLY_GRANTED_TO:
                return mImplicitlyGrantedTo[positionInCategory];
            case CATEGORY_DENIED_TO:
                return mDeniedTo[positionInCategory];
            case CATEGORY_ENFORCED_BY:
                return mEnforcingComponents[positionInCategory];
            }
            return null;
        }

        @Override
        public int getViewTypeCount() {
            return 4; // category header + details header + 2 line item with icon + loading indicator
        }
    };
}