/* * The MIT License (MIT) * * Copyright 2016 Arnab Chakraborty. http://arnab.ch * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.anbox.appmgr; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.support.v4.content.AsyncTaskLoader; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Comparator; /** * @credit http://developer.android.com/reference/android/content/AsyncTaskLoader.html */ public class AppsLoader extends AsyncTaskLoader> { ArrayList mInstalledApps; final PackageManager mPm; PackageIntentReceiver mPackageObserver; public AppsLoader(Context context) { super(context); mPm = context.getPackageManager(); } @Override public ArrayList loadInBackground() { // retrieve the list of installed applications List apps = mPm.getInstalledApplications(0); if (apps == null) { apps = new ArrayList(); } final Context context = getContext(); // create corresponding apps and load their labels ArrayList items = new ArrayList(apps.size()); for (int i = 0; i < apps.size(); i++) { String pkg = apps.get(i).packageName; // only apps which are launchable if (context.getPackageManager().getLaunchIntentForPackage(pkg) != null) { AppModel app = new AppModel(context, apps.get(i)); app.loadLabel(context); items.add(app); } } // sort the list Collections.sort(items, ALPHA_COMPARATOR); return items; } @Override public void deliverResult(ArrayList apps) { if (isReset()) { // An async query came in while the loader is stopped. We // don't need the result. if (apps != null) { onReleaseResources(apps); } } ArrayList oldApps = apps; mInstalledApps = apps; if (isStarted()) { // If the Loader is currently started, we can immediately // deliver its results. super.deliverResult(apps); } // At this point we can release the resources associated with // 'oldApps' if needed; now that the new result is delivered we // know that it is no longer in use. if (oldApps != null) { onReleaseResources(oldApps); } } @Override protected void onStartLoading() { if (mInstalledApps != null) { // If we currently have a result available, deliver it // immediately. deliverResult(mInstalledApps); } // watch for changes in app install and uninstall operation if (mPackageObserver == null) { mPackageObserver = new PackageIntentReceiver(this); } if (takeContentChanged() || mInstalledApps == null ) { // If the data has changed since the last time it was loaded // or is not currently available, start a load. forceLoad(); } } @Override protected void onStopLoading() { // Attempt to cancel the current load task if possible. cancelLoad(); } @Override public void onCanceled(ArrayList apps) { super.onCanceled(apps); // At this point we can release the resources associated with 'apps' // if needed. onReleaseResources(apps); } @Override protected void onReset() { // Ensure the loader is stopped onStopLoading(); // At this point we can release the resources associated with 'apps' // if needed. if (mInstalledApps != null) { onReleaseResources(mInstalledApps); mInstalledApps = null; } // Stop monitoring for changes. if (mPackageObserver != null) { getContext().unregisterReceiver(mPackageObserver); mPackageObserver = null; } } /** * Helper method to do the cleanup work if needed, for example if we're * using Cursor, then we should be closing it here * * @param apps */ protected void onReleaseResources(ArrayList apps) { // do nothing } /** * Perform alphabetical comparison of application entry objects. */ public static final Comparator ALPHA_COMPARATOR = new Comparator() { private final Collator sCollator = Collator.getInstance(); @Override public int compare(AppModel object1, AppModel object2) { return sCollator.compare(object1.getLabel(), object2.getLabel()); } }; }