FileDocCategorySizeDatePackage
ManageApplications.javaAPI DocAndroid 1.5 API65709Wed May 06 22:42:48 BST 2009com.android.settings

ManageApplications

public class ManageApplications extends android.app.ListActivity implements DialogInterface.OnClickListener, android.widget.AdapterView.OnItemClickListener, DialogInterface.OnCancelListener
Activity to pick an application that will be used to display installation information and options to uninstall/delete user data for system applications. This activity can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE intent. Initially a compute in progress message is displayed while the application retrieves the list of application information from the PackageManager. The size information for each package is refreshed to the screen. The resource(app description and icon) information for each package is not available yet, so some default values for size icon and descriptions are used initially. Later the resource information for each application is retrieved and dynamically updated on the screen. A Broadcast receiver registers for package additions or deletions when the activity is in focus. If the user installs or deletes packages when the activity has focus, the receiver gets notified and proceeds to add/delete these packages from the list on the screen. This is an unlikely scenario but could happen. The entire list gets created every time the activity's onStart gets invoked. This is to avoid having the receiver for the entire life cycle of the application. The applications can be sorted either alphabetically or based on size(descending). If this activity gets launched under low memory situations(A low memory notification dispatches intent ACTION_MANAGE_PACKAGE_STORAGE) the list is sorted per size. If the user selects an application, extended info(like size, uninstall/clear data options, permissions info etc.,) is displayed via the InstalledAppDetails activity.

Fields Summary
private static final String
TAG
private boolean
localLOGV
private static final boolean
DEBUG_SIZE
private static final boolean
DEBUG_TIME
public static final String
APP_PKG_PREFIX
public static final String
APP_PKG_NAME
public static final String
APP_CHG
private static final String
ATTR_PKG_NAME
private static final String
ATTR_APP_PKG_STATS
private static final int
INSTALLED_APP_DETAILS
private static final int
MENU_OPTIONS_BASE
public static final int
SORT_ORDER_ALPHA
public static final int
SORT_ORDER_SIZE
public static final int
FILTER_APPS_ALL
public static final int
FILTER_APPS_THIRD_PARTY
public static final int
FILTER_APPS_RUNNING
public static final int
FILTER_OPTIONS
android.app.AlertDialog
mAlertDlg
private int
mSortOrder
int
mFilterApps
private AppInfoAdapter
mAppInfoAdapter
private static final int
HANDLER_MESSAGE_BASE
private static final int
INIT_PKG_INFO
private static final int
COMPUTE_PKG_SIZE_DONE
private static final int
REMOVE_PKG
private static final int
REORDER_LIST
private static final int
ADD_PKG_START
private static final int
ADD_PKG_DONE
private static final int
REFRESH_APP_RESOURCE
private static final int
REFRESH_DONE
private static final int
NEXT_LOAD_STEP
private static final int
COMPUTE_END
private PkgSizeObserver
mObserver
private android.content.pm.PackageManager
mPm
private PackageIntentReceiver
mReceiver
private boolean
mComputeSizes
private android.graphics.drawable.Drawable
mDefaultAppIcon
private static final int
DLG_BASE
private static final int
DLG_LOADING
private CharSequence
mInvalidSizeStr
private CharSequence
mComputingSizeStr
private Map
mAddRemoveMap
private android.view.LayoutInflater
mInflater
private static final int
SIZE_INVALID
private boolean
DEBUG_PKG_DELAY
ResourceLoaderThread
mResourceThread
private TaskRunner
mSizeComputor
String
mCurrentPkgName
private Map
mAppPropCache
private android.widget.TextView
mEmptyView
private boolean
mLoadLabels
private boolean
mSizesFirst
private android.widget.ListView
mListView
private boolean
mJustCreated
private boolean
mFirst
private long
mLoadTimeStart
private android.os.Handler
mHandler
Constructors Summary
Methods Summary
private voidclearMessagesInHandler()

        mHandler.removeMessages(INIT_PKG_INFO);
        mHandler.removeMessages(COMPUTE_PKG_SIZE_DONE);
        mHandler.removeMessages(REMOVE_PKG);
        mHandler.removeMessages(REORDER_LIST);
        mHandler.removeMessages(ADD_PKG_START);
        mHandler.removeMessages(ADD_PKG_DONE);
        mHandler.removeMessages(REFRESH_APP_RESOURCE);
        mHandler.removeMessages(REFRESH_DONE);
        mHandler.removeMessages(NEXT_LOAD_STEP);
        mHandler.removeMessages(COMPUTE_END);
    
private voiddismissLoadingMsg()

        if(localLOGV) Log.i(TAG, "Dismissing Loading message");
        dismissDialog(DLG_LOADING);
        if (DEBUG_TIME) Log.i(TAG, "Displayed loading message for "+
                (SystemClock.elapsedRealtime() - mLoadTimeStart));
    
private voiddoneLoadingData()

        setProgressBarIndeterminateVisibility(false);
    
java.util.ListgetFilteredApps(java.util.List pAppList, int filterOption)

        List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
        if(pAppList == null) {
            return retList;
        }
        if (filterOption == FILTER_APPS_THIRD_PARTY) {
            List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
            for (ApplicationInfo appInfo : pAppList) {
                boolean flag = false;
                if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                    // Updated system app
                    flag = true;
                } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    // Non-system app
                    flag = true;
                }
                if (flag) {
                    appList.add(appInfo);
                }
            }
            return appList;
        } else if (filterOption == FILTER_APPS_RUNNING) {
            List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
            List<ActivityManager.RunningAppProcessInfo> procList = getRunningAppProcessesList();
            if ((procList == null) || (procList.size() == 0)) {
                return appList;
            }
            // Retrieve running processes from ActivityManager
            HashMap<String, ActivityManager.RunningAppProcessInfo> runningMap = 
                new HashMap<String, ActivityManager.RunningAppProcessInfo>();
            for (ActivityManager.RunningAppProcessInfo appProcInfo : procList) {
                if ((appProcInfo != null)  && (appProcInfo.pkgList != null)){
                    int size = appProcInfo.pkgList.length;
                    for (int i = 0; i < size; i++) {
                        runningMap.put(appProcInfo.pkgList[i], appProcInfo);
                    }
                }
            }
            // Query list to find running processes in current list
            for (ApplicationInfo appInfo : pAppList) {
                if (runningMap.get(appInfo.packageName) != null) {
                    appList.add(appInfo);
                }
            }
            return appList;
        } else {
            return pAppList;
        }
    
java.util.ListgetInstalledApps(int filterOption)

        List<ApplicationInfo> installedAppList = mPm.getInstalledApplications(
                PackageManager.GET_UNINSTALLED_PACKAGES);
        if (installedAppList == null) {
            return new ArrayList<ApplicationInfo> ();
        }
        if (filterOption == FILTER_APPS_THIRD_PARTY) {
            List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
            for (ApplicationInfo appInfo : installedAppList) {
                boolean flag = false;
                if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                    // Updated system app
                    flag = true;
                } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                    // Non-system app
                    flag = true;
                }
                if (flag) {
                    appList.add(appInfo);
                }
            }
            return appList;
        } else if (filterOption == FILTER_APPS_RUNNING) {
            List<ApplicationInfo> appList =new ArrayList<ApplicationInfo> ();
            List<ActivityManager.RunningAppProcessInfo> procList = getRunningAppProcessesList();
            if ((procList == null) || (procList.size() == 0)) {
                return appList;
            }
            // Retrieve running processes from ActivityManager
            for (ActivityManager.RunningAppProcessInfo appProcInfo : procList) {
                if ((appProcInfo != null)  && (appProcInfo.pkgList != null)){
                    int size = appProcInfo.pkgList.length;
                    for (int i = 0; i < size; i++) {
                        ApplicationInfo appInfo = null;
                        try {
                            appInfo = mPm.getApplicationInfo(appProcInfo.pkgList[i], 
                                    PackageManager.GET_UNINSTALLED_PACKAGES);
                        } catch (NameNotFoundException e) {
                           Log.w(TAG, "Error retrieving ApplicationInfo for pkg:"+appProcInfo.pkgList[i]);
                           continue;
                        }
                        if(appInfo != null) {
                            appList.add(appInfo);
                        }
                    }
                }
            }
            return appList;
        } else {
            return installedAppList;
        }
    
private java.util.ListgetRunningAppProcessesList()

        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        return am.getRunningAppProcesses();
    
private voidinitAppList(int filterOption)

        initAppList(null, filterOption);
    
private voidinitAppList(java.util.List appList, int filterOption)

        setProgressBarIndeterminateVisibility(true);
        mComputeSizes = false;
        mLoadLabels = false;
        // Initialize lists
        mAddRemoveMap = new TreeMap<String, Boolean>();
        mAppInfoAdapter.initMapFromList(appList, filterOption);
    
private voidinitComputeSizes()

         // Initiate compute package sizes
        if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
        if ((mSizeComputor != null) && (mSizeComputor.isAlive())) {
            mSizeComputor.setAbort();
        }
        List<ApplicationInfo> appList = mAppInfoAdapter.getBaseAppList();
        if ((appList != null) && (appList.size()) > 0) {
            mSizeComputor = new TaskRunner(appList);
        } else {
            mComputeSizes = true;
        }
    
private voidinitResourceThread()

        if ((mResourceThread != null) && mResourceThread.isAlive()) {
            mResourceThread.setAbort();
        }
        mResourceThread = new ResourceLoaderThread();
        List<ApplicationInfo> appList = mAppInfoAdapter.getBaseAppList();
        if ((appList != null) && (appList.size()) > 0) {
            mResourceThread.loadAllResources(appList);
        }
    
public voidonCancel(android.content.DialogInterface dialog)

        finish();
    
public voidonClick(android.content.DialogInterface dialog, int which)

        int newOption;
        switch (which) {
        // Make sure that values of 0, 1, 2 match options all, running, third_party when
        // created via the AlertDialog.Builder
        case 0:
            newOption = FILTER_APPS_ALL;
            break;
        case 1:
            newOption = FILTER_APPS_RUNNING;
            break;
        case 2:
            newOption = FILTER_APPS_THIRD_PARTY;
            break;
        default:
            return;
        }
        mAlertDlg.dismiss();
        sendMessageToHandler(REORDER_LIST, newOption);
    
public voidonConfigurationChanged(android.content.res.Configuration newConfig)

        super.onConfigurationChanged(newConfig);
    
protected voidonCreate(android.os.Bundle savedInstanceState)

        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        String action = intent.getAction();
        if (action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
            mSortOrder = SORT_ORDER_SIZE;
            mSizesFirst = true;
        }
        mPm = getPackageManager();
        // initialize some window features
        requestWindowFeature(Window.FEATURE_RIGHT_ICON);
        requestWindowFeature(Window.FEATURE_PROGRESS);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.compute_sizes);
        showLoadingMsg();
        mDefaultAppIcon =Resources.getSystem().getDrawable(
                com.android.internal.R.drawable.sym_def_app_icon);
        mInvalidSizeStr = getText(R.string.invalid_size_value);
        mComputingSizeStr = getText(R.string.computing_size);
        // initialize the inflater
        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mReceiver = new PackageIntentReceiver();
        mEmptyView = (TextView) findViewById(R.id.empty_view);
        mObserver = new PkgSizeObserver();
        // Create adapter and list view here
        List<ApplicationInfo> appList = getInstalledApps(mSortOrder);
        mAppInfoAdapter = new AppInfoAdapter(this, appList);
        ListView lv= (ListView) findViewById(android.R.id.list);
        lv.setOnItemClickListener(this);
        lv.setSaveEnabled(true);
        lv.setItemsCanFocus(true);
        lv.setOnItemClickListener(this);
        mListView = lv;
    
public android.app.DialogonCreateDialog(int id)

        if (id == DLG_LOADING) {
            ProgressDialog dlg = new ProgressDialog(this);
            dlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            dlg.setMessage(getText(R.string.loading));
            dlg.setIndeterminate(true);        
            dlg.setOnCancelListener(this);
            return dlg;
        }
        return null;
    
public booleanonCreateOptionsMenu(android.view.Menu menu)

        menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha)
                .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
        menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
                .setIcon(android.R.drawable.ic_menu_sort_by_size); 
        menu.add(0, FILTER_OPTIONS, 3, R.string.filter)
                .setIcon(R.drawable.ic_menu_filter_settings);
        return true;
    
public voidonItemClick(android.widget.AdapterView parent, android.view.View view, int position, long id)

        ApplicationInfo info = (ApplicationInfo)mAppInfoAdapter.getItem(position);
        mCurrentPkgName = info.packageName;
        startApplicationDetailsActivity();
    
public booleanonOptionsItemSelected(android.view.MenuItem item)

        int menuId = item.getItemId();
        if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
            sendMessageToHandler(REORDER_LIST, menuId);
        } else if (menuId == FILTER_OPTIONS) {
            if (mAlertDlg == null) {
                mAlertDlg = new AlertDialog.Builder(this).
                        setTitle(R.string.filter_dlg_title).
                        setNeutralButton(R.string.cancel, this).
                        setSingleChoiceItems(new CharSequence[] {getText(R.string.filter_apps_all),
                                getText(R.string.filter_apps_running),
                                getText(R.string.filter_apps_third_party)},
                                -1, this).
                        create();
            }
            mAlertDlg.show();
        }
        return true;
    
public booleanonPrepareOptionsMenu(android.view.Menu menu)

        if (mFirst) {
            menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
            menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
            menu.findItem(FILTER_OPTIONS).setVisible(true);
            return true;
        }
        return false;
    
public voidonStart()

        super.onStart();
        // register receiver
        mReceiver.registerReceiver();
        sendMessageToHandler(INIT_PKG_INFO);
    
public voidonStop()

        super.onStop();
        // Stop the background threads
        if (mResourceThread != null) {
            mResourceThread.setAbort();
        }
        if (mSizeComputor != null) {
            mSizeComputor.setAbort();
        }
        // clear all messages related to application list
        clearMessagesInHandler();
        // register receiver here
        unregisterReceiver(mReceiver);        
        mAppPropCache = mAppInfoAdapter.mAppPropMap;
    
private voidsendMessageToHandler(int msgId, int arg1)

        Message msg = mHandler.obtainMessage(msgId);
        msg.arg1 = arg1;
        mHandler.sendMessage(msg);
    
private voidsendMessageToHandler(int msgId, android.os.Bundle data)

        Message msg = mHandler.obtainMessage(msgId);
        msg.setData(data);
        mHandler.sendMessage(msg);
    
private voidsendMessageToHandler(int msgId)

        mHandler.sendEmptyMessage(msgId);
    
private voidshowEmptyViewIfListEmpty()

        if (localLOGV) Log.i(TAG, "Checking for empty view");
        if (mAppInfoAdapter.getCount() > 0) {
            mListView.setVisibility(View.VISIBLE);
            mEmptyView.setVisibility(View.GONE);
        } else {
            mListView.setVisibility(View.GONE);
            mEmptyView.setVisibility(View.VISIBLE);
        }
    
private voidshowLoadingMsg()

        if (DEBUG_TIME) {
            mLoadTimeStart = SystemClock.elapsedRealtime();
        }
        showDialog(DLG_LOADING); 
        if(localLOGV) Log.i(TAG, "Displaying Loading message");
    
private voidstartApplicationDetailsActivity()

        // Create intent to start new activity
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setClass(this, InstalledAppDetails.class);
        intent.putExtra(APP_PKG_NAME, mCurrentPkgName);
        // start new activity to display extended information
        startActivityForResult(intent, INSTALLED_APP_DETAILS);
    
private booleanupdateAppList(java.util.List newList)

        if ((newList == null) || (mAppPropCache == null)) {
            return false;
        }
        Set<String> existingList = new HashSet<String>();
        boolean ret = false;
        // Loop over new list and find out common elements between old and new lists
        for (ApplicationInfo info : newList) {
            String pkgName = info.packageName;
            AppInfo aInfo = mAppPropCache.get(pkgName);
            if (aInfo != null) {
                existingList.add(pkgName);
            } else {
                // New package. update info by refreshing
                if (localLOGV) Log.i(TAG, "New pkg :"+pkgName+" installed when paused");
                updatePackageList(Intent.ACTION_PACKAGE_ADDED, pkgName);
                ret = true;
            }
        }
        // Loop over old list and figure out state entries
        List<String> deletedList = null;
        Set<String> staleList = mAppPropCache.keySet();
        for (String pkgName : staleList) {
            if (!existingList.contains(pkgName)) {
                if (localLOGV) Log.i(TAG, "Pkg :"+pkgName+" deleted when paused");
                if (deletedList == null) {
                    deletedList = new ArrayList<String>();
                    deletedList.add(pkgName);
                }
                ret = true;
            }
        }
        // Delete right away
        if (deletedList != null) {
            mAppInfoAdapter.removeFromList(deletedList);
        }
        return ret;
    
private voidupdatePackageList(java.lang.String actionStr, java.lang.String pkgName)

        // technically we dont have to invoke handler since onReceive is invoked on
        // the main thread but doing it here for better clarity
        if (Intent.ACTION_PACKAGE_ADDED.equalsIgnoreCase(actionStr)) {
            Bundle data = new Bundle();
            data.putString(ATTR_PKG_NAME, pkgName);
            sendMessageToHandler(ADD_PKG_START, data);
        } else if (Intent.ACTION_PACKAGE_REMOVED.equalsIgnoreCase(actionStr)) {
            Bundle data = new Bundle();
            data.putString(ATTR_PKG_NAME, pkgName);
            sendMessageToHandler(REMOVE_PKG, data);
        }