+++ /dev/null
-/*
- Copyright (C) 2014 Samsung Electronics Polska Sp. z o.o.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU AFFERO General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- You may obtain a copy of the License at
-
- http://www.gnu.org/licenses/agpl-3.0.txt
-
- 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.samsung.srpol.loader;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.Signature;
-import android.content.res.XmlResourceParser;
-import android.support.v4.content.AsyncTaskLoader;
-
-import com.samsung.srpol.R;
-import com.samsung.srpol.data.Category;
-import com.samsung.srpol.data.Subcategory;
-
-/**
- * A custom Loader that loads all of the installed applications.
- */
-public class AppListLoader extends AsyncTaskLoader<List<AppDetails>> {
- private static final String SYSTEM_UI = "com.android.systemui";
- private static final String PHONE = "com.android.phone";
-
- public static final String PREF_INCLUDE_SYSTEM_APPS = "include_system_apps";
-
- private final PackageManager mPm;
-
- private static List<AppDetails> mAppDetailsList = null;
- private static List<Category> mCategories;
- private static ArrayList<Subcategory> mSubcategories;
- private static HashMap<String, Integer> mAllPermissionsHash;
-
- private PackageIntentReceiver mPackageObserver;
- private boolean mWasDataReloaded = true;
- private static OnAppRemoveListener mChangeListener = null;
-
- public AppListLoader(Context context) {
- super(context);
-
- if (mCategories == null || mSubcategories == null
- || mAllPermissionsHash == null)
- initCategories(context);
-
- mPm = getContext().getPackageManager();
- }
-
- private void initCategories(Context context) {
- mCategories = new ArrayList<Category>();
- mSubcategories = new ArrayList<Subcategory>();
- Subcategory.resetGenerator();
-
- // Reading "data send" subcategory as it is common
- try {
- XmlResourceParser parser = context.getResources().getXml(
- R.xml.data_send_subcategory);
- int eventType = 0;
- while (eventType != XmlResourceParser.END_DOCUMENT
- && eventType != XmlResourceParser.START_TAG)
- eventType = parser.next();
- if (eventType != XmlResourceParser.END_DOCUMENT) {
- Subcategory subcategory = readSubCategory(parser);
- mSubcategories.add(subcategory);
- }
- } catch (XmlPullParserException ex) {
- ex.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // Reading all categories and subcategories from xml
- try {
- XmlResourceParser parser = context.getResources().getXml(
- R.xml.categories);
- int eventType = 0;
- while (eventType != XmlResourceParser.END_DOCUMENT
- && eventType != XmlResourceParser.START_TAG)
- eventType = parser.next();
- if (eventType != XmlResourceParser.END_DOCUMENT) {
- parser.require(XmlResourceParser.START_TAG, null, "container");
- while (parser.next() != XmlResourceParser.END_TAG) {
- if (parser.getEventType() != XmlResourceParser.START_TAG)
- continue;
- if (!parser.getName().equals("category"))
- continue;
- Category cat = readCategory(parser);
- mCategories.add(cat);
- mSubcategories.addAll(cat.getSubCategories());
- }
- }
- } catch (XmlPullParserException ex) {
- ex.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- mAllPermissionsHash = new HashMap<String, Integer>();
- for (Subcategory subcat : mSubcategories) {
- for (String perm : subcat.getPermissions()) {
- Integer value = mAllPermissionsHash.get(perm);
- if (value == null) {
- mAllPermissionsHash.put(perm, Integer.valueOf(subcat.getId()));
- } else {
- value |= subcat.getId();
- mAllPermissionsHash.put(perm, value);
- }
- }
- }
- }
-
- private Category readCategory(XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- parser.require(XmlResourceParser.START_TAG, null, "category");
- String title = null, header = null, description = null, shortDescription = null, link = null;
- int icon = 0;
- boolean dataSend = false;
- ArrayList<Subcategory> subCategories = new ArrayList<Subcategory>();
-
- while (parser.next() != XmlResourceParser.END_TAG) {
- if (parser.getEventType() != XmlResourceParser.START_TAG)
- continue;
- String name = parser.getName();
- if (name.equals("title")) {
- title = readTextElement(parser, name);
- } else if (name.equals("header")) {
- header = readTextElement(parser, name);
- } else if (name.equals("short_description")) {
- shortDescription = readTextElement(parser, name);
- } else if (name.equals("description")) {
- description = readTextElement(parser, name);
- } else if (name.equals("icon")) {
- icon = getContext().getResources().getIdentifier(
- readTextElement(parser, name), "drawable",
- getContext().getPackageName());
- } else if (name.equals("link")) {
- link = readTextElement(parser, name);
- } else if (name.equals("dataSend")) {
- dataSend = Boolean.parseBoolean(readTextElement(parser, name));
- } else if (name.equals("subcategories")) {
- while (parser.next() != XmlResourceParser.END_TAG) {
- subCategories.add(readSubCategory(parser));
- }
- } else
- skip(parser);
- }
- return new Category(getContext(), title, header, shortDescription,
- description, icon, link, dataSend, subCategories);
- }
-
- private Subcategory readSubCategory(XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- parser.require(XmlResourceParser.START_TAG, null, "subcategory");
- String header = null, description = null, icon = null;
- ArrayList<String> permissions = new ArrayList<String>();
-
- while (parser.next() != XmlResourceParser.END_TAG) {
- if (parser.getEventType() != XmlResourceParser.START_TAG)
- continue;
- String name = parser.getName();
- if (name.equals("header")) {
- header = readTextElement(parser, name);
- } else if (name.equals("description")) {
- description = readTextElement(parser, name);
- } else if (name.equals("icon")) {
- icon = readTextElement(parser, name);
- } else if (name.equals("permissions")) {
- while (parser.next() != XmlResourceParser.END_TAG) {
- permissions.add(readTextElement(parser, "item"));
- }
- } else
- skip(parser);
- }
-
- return new Subcategory(getContext(), header, description, icon,
- permissions);
- }
-
- private String readTextElement(XmlResourceParser parser, String element)
- throws XmlPullParserException, IOException {
- parser.require(XmlResourceParser.START_TAG, null, element);
- String title = readText(parser);
- parser.require(XmlResourceParser.END_TAG, null, element);
- return title;
- }
-
- private String readText(XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- String result = "";
- if (parser.next() == XmlResourceParser.TEXT) {
- result = parser.getText();
- parser.nextTag();
- }
- return result;
- }
-
- private void skip(XmlResourceParser parser) throws XmlPullParserException,
- IOException {
- if (parser.getEventType() != XmlResourceParser.START_TAG) {
- throw new IllegalStateException();
- }
- int depth = 1;
- while (depth != 0) {
- switch (parser.next()) {
- case XmlResourceParser.END_TAG:
- depth--;
- break;
- case XmlResourceParser.START_TAG:
- depth++;
- break;
- }
- }
- }
-
- /**
- * Get Signature keys of given package
- *
- * @param packageName
- * package name to retrieve signature keys
- * @return Signature[] containing given package name signature keys
- */
- private Signature[] getSignature(String packageName) {
-
- try {
- PackageInfo packageInfo = getPm().getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES);
- Signature[] sigs = packageInfo.signatures;
- return sigs;
- } catch (NameNotFoundException e) {
- return null;
- }
-
- }
-
- /**
- * Get Signature keys for given PackageInfo
- *
- * @param packageInfo
- * PackageInfo to retrieve signature keys
- * @return Signature[] containing given PackageInfo signature keys
- */
- @SuppressWarnings("unused")
- private Signature[] getSignature(PackageInfo packageInfo) {
-
- Signature[] sigs = packageInfo.signatures;
- return sigs;
-
- }
-
- /**
- * Get Platform signature key. we check signature of SystemUI process or
- * Phone process
- *
- * @return Signature platform sign key or null if not found
- */
- @SuppressWarnings("unused")
- private Signature getPlatformSignature() {
- Signature sig = getSignature(SYSTEM_UI)[0];
- if (sig == null) {
- sig = getSignature(PHONE)[0];
- }
- return sig;
- }
-
- /**
- * Filter given ApplicationInfo list only to apps that are not platform
- * signed
- *
- * @param appList
- * List<ApplicationInfo> with a list of apps to filter
- * @return List<ApplicationInfo> filtred app list
- */
- private List<PackageInfo> filterToNotPlatformKeyAppList(List<PackageInfo> packageList) {
- if (packageList != null) {
-
- List<PackageInfo> noPlatformKeyAppList = new ArrayList<PackageInfo>();
- for (PackageInfo packageInfo : packageList) {
- try {
- packageInfo = mPm.getPackageInfo(packageInfo.packageName,
- PackageManager.GET_ACTIVITIES
- | PackageManager.GET_PERMISSIONS
- | PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- continue;
- }
- // Check signature match with SystemUI
- if (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 || (packageInfo.activities != null && packageInfo.activities.length > 0))
- && getPm().checkSignatures(SYSTEM_UI,
- packageInfo.packageName) != PackageManager.SIGNATURE_MATCH) {
- noPlatformKeyAppList.add(packageInfo);
- }
- }
- return noPlatformKeyAppList;
- } else {
- return null;
- }
- }
-
- private PackageInfo getInstalledAppDetails(String packageName) {
- PackageInfo info = null;
- try {
- info = getPm().getPackageInfo(
- packageName,
- PackageManager.GET_META_DATA
- | PackageManager.GET_PERMISSIONS
- | PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- return info;
- }
-
- @Override
- public List<AppDetails> loadInBackground() {
- List<PackageInfo> appList = mPm.getInstalledPackages(0);
-
- appList = filterToNotPlatformKeyAppList(appList);
-
- HashMap<String, AppDetails> appDetailsHash = new HashMap<String, AppDetails>(
- appList.size());
- if (mSubcategories.size() == 0) {
- for (PackageInfo pInfo : appList) {
- appDetailsHash.put(pInfo.packageName, new AppDetails(this,
- pInfo));
- }
- } else {
- for (PackageInfo packageInfo : appList) {
- String[] requestedPermissions = packageInfo.requestedPermissions;
- if (requestedPermissions != null) {
- AppDetails appDetails = appDetailsHash.get(packageInfo.packageName);
- for (String permissionName : requestedPermissions) {
- Integer subcategories = mAllPermissionsHash.get(permissionName);
- if (subcategories != null
- && (appDetails == null || !appDetails.isInAllSubcategories(subcategories))
- && getPm().checkPermission(permissionName,
- packageInfo.packageName) == PackageManager.PERMISSION_GRANTED) {
- if (appDetails == null) {
- appDetails = new AppDetails(this, packageInfo);
- appDetailsHash.put(packageInfo.packageName,
- appDetails);
- }
- appDetails.addSubcategory(subcategories);
- }
- }
- }
- }
- }
- // Sort the list.
- List<AppDetails> list = new ArrayList<AppDetails>(
- appDetailsHash.values());
- Collections.sort(list, AppDetails.SMART_COMPARATOR);
-
- for (Category category : mCategories)
- category.assignAppsToCategory(list);
-
- mWasDataReloaded = true;
- return list;
- }
-
- /**
- * Called when there is new data to deliver to the client. The super class
- * will take care of delivering it; the implementation here just adds a
- * little more logic.
- */
- @Override
- public void deliverResult(List<AppDetails> apps) {
- if (isReset()) {
- apps = null;
- }
- mAppDetailsList = apps;
-
- if (isStarted()) {
- // If the Loader is currently started, we can immediately
- // deliver its results.
- super.deliverResult(apps);
- }
- }
-
- /**
- * Handles a request to start the Loader.
- */
- @Override
- protected void onStartLoading() {
- if (mAppDetailsList != null) {
- // If we currently have a result available, deliver it
- // immediately.
- deliverResult(mAppDetailsList);
- }
-
- // Start watching for changes in the app data.
- if (mPackageObserver == null) {
- mPackageObserver = new PackageIntentReceiver(this);
- }
-
- if (takeContentChanged() || mAppDetailsList == null) {
- // If the data has changed since the last time it was loaded
- // or is not currently available, start a load.
- forceLoad();
- }
- }
-
- /**
- * Handles a request to stop the Loader.
- */
- @Override
- protected void onStopLoading() {
- // Attempt to cancel the current load task if possible.
- cancelLoad();
- }
-
- /**
- * Handles a request to completely reset the Loader.
- */
- @Override
- protected void onReset() {
-
- // Ensure the loader is stopped
- onStopLoading();
-
- // Stop monitoring for changes.
- if (mPackageObserver != null) {
- getContext().unregisterReceiver(mPackageObserver);
- mPackageObserver = null;
- }
- }
-
- /**
- * Gets AppDetails from mAppDetailsList for a given PackageName
- *
- * @param packageName
- * PackageName for which to get AppDetails
- * @return AppDetails for given PackageName
- */
- public static AppDetails getAppDetails(String packageName) {
- if (packageName != null && mAppDetailsList != null) {
- for (AppDetails appDetails : mAppDetailsList) {
- if (packageName.equals(appDetails.getAppPackageName())) {
- return appDetails;
- }
- }
- }
- return null;
- }
-
- public static void setOnChangeListener(OnAppRemoveListener listener) {
- mChangeListener = listener;
- }
-
- /**
- * @return the mAppDetailsList
- */
- public static List<AppDetails> getAppDetailsList() {
- return mAppDetailsList;
- }
-
- /**
- * @return the mCategories
- */
- static public List<Category> getCategories() {
- return mCategories;
- }
-
- public static List<Subcategory> getSubcategoriesOfMask(int subcategoriesMask) {
- ArrayList<Subcategory> list = new ArrayList<Subcategory>();
- for (Subcategory subcategory : mSubcategories) {
- if ((subcategoriesMask & subcategory.getId()) > 0) {
- list.add(subcategory);
- }
- }
- return list;
- }
-
- public PackageManager getPm() {
- return mPm;
- }
-
- public interface OnAppRemoveListener {
- public void onPackageRemoved(String packageName);
- }
-
- /**
- * Helper class to look for interesting changes to the installed apps so
- * that the loader can be updated.
- */
- public static class PackageIntentReceiver extends BroadcastReceiver {
- private final AppListLoader mLoader;
-
- public PackageIntentReceiver(AppListLoader loader) {
- mLoader = loader;
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- mLoader.getContext().registerReceiver(this, filter);
- // Register for events related to sdcard installation.
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mLoader.getContext().registerReceiver(this, sdFilter);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(
- Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)) {
- mLoader.onPackagesAdded(intent
- .getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST));
- } else if (intent.getAction().equals(
- Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
- mLoader.onPackagesRemoved(intent
- .getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST));
- } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED))
- mLoader.onPackageRemoved(intent.getData()
- .getSchemeSpecificPart(), true);
- else if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED))
- mLoader.onPackageAdded(
- intent.getData().getSchemeSpecificPart(), true);
- else if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))
- mLoader.onPackageChanged(intent.getData()
- .getSchemeSpecificPart());
- }
- }
-
- public void onPackageRemoved(String packageName, boolean deliverResult) {
- if (mChangeListener != null)
- mChangeListener.onPackageRemoved(packageName);
- for (AppDetails details : mAppDetailsList) {
- if (details.getAppPackageName().equals(packageName)) {
- mAppDetailsList.remove(details);
- for (Category category : mCategories)
- category.removeAppFromList(details);
- if (deliverResult)
- deliverResult(new ArrayList<AppDetails>(mAppDetailsList));
- break;
- }
- }
- }
-
- public void onPackagesRemoved(String[] packageNames) {
- for (String packageName : packageNames) {
- onPackageRemoved(packageName, false);
- }
- deliverResult(new ArrayList<AppDetails>(mAppDetailsList));
- }
-
- public void onPackageChanged(String packageName) {
- for (AppDetails details : mAppDetailsList) {
- if (details.getAppPackageName().equals(packageName)) {
- PackageInfo packageInfo = getInstalledAppDetails(packageName);
- if (packageInfo == null)
- return;
- details.setEnabled(packageInfo.applicationInfo.enabled);
- deliverResult(new ArrayList<AppDetails>(mAppDetailsList));
- break;
- }
- }
- }
-
- public void onPackageAdded(String packageName, boolean deliverResult) {
- PackageInfo packageInfo = getInstalledAppDetails(packageName);
- if (packageInfo == null)
- return;
- AppDetails newPackage = new AppDetails(this, packageInfo);
-
- String[] requestedPermissions = packageInfo.requestedPermissions;
- if (requestedPermissions != null && mSubcategories != null) {
- for (String permissionName : requestedPermissions) {
- Integer subcategories = mAllPermissionsHash.get(permissionName);
- if (subcategories != null
- && getPm().checkPermission(permissionName,
- packageInfo.packageName) == PackageManager.PERMISSION_GRANTED) {
- newPackage.addSubcategory(subcategories);
- }
- }
- }
- mAppDetailsList.add(newPackage);
-
- for (Category category : mCategories)
- category.addApplicationToCategory(newPackage);
- if (deliverResult)
- deliverResult(new ArrayList<AppDetails>(mAppDetailsList));
- }
-
- public void onPackagesAdded(String[] packageNames) {
- for (String packageStr : packageNames) {
- onPackageAdded(packageStr, false);
- }
-
- deliverResult(new ArrayList<AppDetails>(mAppDetailsList));
- }
-
- public boolean wasDataReloaded() {
- return mWasDataReloaded;
- }
-
- public void resetWasDataReloaded() {
- mWasDataReloaded = false;
- }
-}
\ No newline at end of file