Code drop from //branches/cupcake/...@124589
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
index 8389502..f1550f9 100644
--- a/src/com/android/settings/ManageApplications.java
+++ b/src/com/android/settings/ManageApplications.java
@@ -18,8 +18,12 @@
 
 import com.android.settings.R;
 import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
@@ -27,320 +31,954 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.format.Formatter;
 import android.util.Config;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
 import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.ImageView;
 import android.widget.ListView;
-import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.AdapterView.OnItemClickListener;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 
 /**
  * Activity to pick an application that will be used to display installation information and
- * options to upgrade/uninstall/delete user data for system applications.
+ * 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 size information of installed packages which is done asynchronously through a 
- *  handler. Once the computation is done package resource information is retrieved 
- *  and then the information is displayed on the screen. All 
- *  messages are passed through a Handler object.
- *  Known issue: There could be some ordering issues when installing/uninstalling
- *  applications when the application list is being scanned.
+ *  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.
+ *  This activity passes the package name and size information to the 
+ *  InstalledAppDetailsActivity to avoid recomputation of the package size information.
  */
-public class ManageApplications extends Activity implements SimpleAdapter.ViewBinder, OnItemClickListener {
+public class ManageApplications extends ListActivity implements
+        OnItemClickListener, DialogInterface.OnCancelListener {
+    // TAG for this activity
     private static final String TAG = "ManageApplications";
-    //Application prefix information
-    public static final String APP_PKG_PREFIX="com.android.settings.";
-    public static final String APP_PKG_NAME=APP_PKG_PREFIX+"ApplicationPkgName";
-    public static final String APP_PKG_SIZE= APP_PKG_PREFIX+"size";
-    public static final String APP_CHG=APP_PKG_PREFIX+"changed";
     
-    //constant value that can be used to check return code from sub activity.
-    private static final int INSTALLED_APP_DETAILS = 1;
-     //application attributes passed to sub activity that displays more app info
-    private static final String KEY_APP_NAME = "ApplicationName";
-    private static final String KEY_APP_ICON = "ApplicationIcon";
-    private static final String KEY_APP_DESC = "ApplicationDescription";
-    private static final String KEY_APP_SIZE= "ApplicationSize";
-    //sort order that can be changed through the menu
-    public static final int SORT_ORDER_ALPHA = 0;
-    public static final int SORT_ORDER_SIZE = 1;
-   //key and resource values used in constructing map for SimpleAdapter
-    private static final String sKeys[] = new String[] { KEY_APP_NAME, KEY_APP_ICON, 
-            KEY_APP_DESC, KEY_APP_SIZE};
-    private static final int sResourceIds[] = new int[] { R.id.app_name, R.id.app_icon, 
-            R.id.app_description, R.id.app_size};
-    //List of ApplicationInfo objects for various applications
-    private List<ApplicationInfo> mAppList;
-    //SimpleAdapter used for managing items in the list
-    private SimpleAdapter mAppAdapter;
-    //map used to store size information which is used for displaying size information
-    //in this activity as well as the subactivity. this is to avoid invoking package manager
-    //api to retrieve size information
-    private HashMap<String, PackageStats> mSizeMap;
-    private HashMap<String, Map<String, ?> > mAppAdapterMap;
-    //sort order
-    private int mSortOrder = SORT_ORDER_ALPHA;
-    //log information boolean
+    // log information boolean
     private boolean localLOGV = Config.LOGV || false;
-    private ApplicationInfo mCurrentPkg;
-    private int mCurrentPkgIdx = 0;
-    private static final int COMPUTE_PKG_SIZE_START = 1;
-    private static final int COMPUTE_PKG_SIZE_DONE = 2;
-    private static final int REMOVE_PKG=3;
-    private static final int REORDER_LIST=4;
-    private static final int ADD_PKG=5;
-    private static final String ATTR_APP_IDX="ApplicationIndex";
-    private static final String ATTR_CHAINED="Chained";
+    
+    // attributes used as keys when passing values to InstalledAppDetails activity
+    public static final String APP_PKG_PREFIX = "com.android.settings.";
+    public static final String APP_PKG_NAME = APP_PKG_PREFIX+"ApplicationPkgName";
+    public static final String APP_PKG_SIZE = APP_PKG_PREFIX+"size";
+    public static final String APP_CHG = APP_PKG_PREFIX+"changed";
+    
+    // attribute name used in receiver for tagging names of added/deleted packages
     private static final String ATTR_PKG_NAME="PackageName";
+    private static final String ATTR_APP_PKG_STATS="ApplicationPackageStats";
+    
+    // constant value that can be used to check return code from sub activity.
+    private static final int INSTALLED_APP_DETAILS = 1;
+    
+    // sort order that can be changed through the menu can be sorted alphabetically
+    // or size(descending)
+    private static final int MENU_OPTIONS_BASE = 0;
+    public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 0;
+    public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 1;
+    // Filter options used for displayed list of applications
+    public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 2;
+    public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 3;
+    public static final int FILTER_APPS_RUNNING = MENU_OPTIONS_BASE + 4;
+    // sort order
+    private int mSortOrder = SORT_ORDER_ALPHA;
+    // Filter value
+    int mFilterApps = FILTER_APPS_ALL;
+    
+    // Custom Adapter used for managing items in the list
+    private AppInfoAdapter mAppInfoAdapter;
+    
+    // messages posted to the handler
+    private static final int HANDLER_MESSAGE_BASE = 0;
+    private static final int COMPUTE_PKG_SIZE_START = HANDLER_MESSAGE_BASE+1;
+    private static final int COMPUTE_PKG_SIZE_DONE = HANDLER_MESSAGE_BASE+2;
+    private static final int REMOVE_PKG = HANDLER_MESSAGE_BASE+3;
+    private static final int REORDER_LIST = HANDLER_MESSAGE_BASE+4;
+    private static final int ADD_PKG_START = HANDLER_MESSAGE_BASE+5;
+    private static final int ADD_PKG_DONE = HANDLER_MESSAGE_BASE+6;
+    private static final int REFRESH_ICONS = HANDLER_MESSAGE_BASE+7;
+    
+    // observer object used for computing pkg sizes
     private PkgSizeObserver mObserver;
+    // local handle to PackageManager
     private PackageManager mPm;
+    // Broadcast Receiver object that receives notifications for added/deleted
+    // packages
     private PackageIntentReceiver mReceiver;
+    // atomic variable used to track if computing pkg sizes is in progress. should be volatile?
+    
     private boolean mDoneIniting = false;
-    private String mKbStr;
-    private String  mMbStr;
-    private String mBStr;
+    // default icon thats used when displaying applications initially before resource info is
+    // retrieved
+    private Drawable mDefaultAppIcon;
+    
+    // temporary dialog displayed while the application info loads
+    private ProgressDialog mLoadingDlg = null;
+    
+    // compute index used to track the application size computations
+    private int mComputeIndex;
+    
+    // Size resource used for packages whose size computation failed for some reason
+    private CharSequence mInvalidSizeStr;
+    private CharSequence mComputingSizeStr;
+    
+    // map used to store list of added and removed packages. Immutable Boolean
+    // variables indicate if a package has been added or removed. If a package is
+    // added or deleted multiple times a single entry with the latest operation will
+    // be recorded in the map.
+    private Map<String, Boolean> mAddRemoveMap;
+    
+    // layout inflater object used to inflate views
+    private LayoutInflater mInflater;
+    
+    // invalid size value used initially and also when size retrieval through PackageManager
+    // fails for whatever reason
+    private static final int SIZE_INVALID = -1;
+    
+    // debug boolean variable to test delays from PackageManager API's
+    private boolean DEBUG_PKG_DELAY = false;
+    
+    // Thread to load resources
+    ResourceLoaderThread mResourceThread;
+    
+    String mCurrentPkgName;
+    
+    //TODO implement a cache system
+    private Map<String, AppInfo> mAppPropCache;
     
     /*
      * Handler class to handle messages for various operations
+     * Most of the operations that effect Application related data
+     * are posted as messages to the handler to avoid synchronization
+     * when accessing these structures.
+     * When the size retrieval gets kicked off for the first time, a COMPUTE_PKG_SIZE_START
+     * message is posted to the handler which invokes the getSizeInfo for the pkg at index 0
+     * When the PackageManager's asynchronous call back through
+     * PkgSizeObserver.onGetStatsCompleted gets invoked, the application resources like
+     * label, description, icon etc., is loaded in the same thread and these values are
+     * set on the observer. The observer then posts a COMPUTE_PKG_SIZE_DONE message
+     * to the handler. This information is updated on the AppInfoAdapter associated with
+     * the list view of this activity and size info retrieval is initiated for the next package as 
+     * indicated by mComputeIndex
+     * When a package gets added while the activity has focus, the PkgSizeObserver posts
+     * ADD_PKG_START message to the handler.  If the computation is not in progress, the size
+     * is retrieved for the newly added package through the observer object and the newly
+     * installed app info is updated on the screen. If the computation is still in progress
+     * the package is added to an internal structure and action deferred till the computation
+     * is done for all the packages. 
+     * When a package gets deleted, REMOVE_PKG is posted to the handler
+     *  if computation is not in progress(as indicated by
+     * mDoneIniting), the package is deleted from the displayed list of apps. If computation is
+     * still in progress the package is added to an internal structure and action deferred till
+     * the computation is done for all packages.
+     * When the sizes of all packages is computed, the newly
+     * added or removed packages are processed in order.
+     * If the user changes the order in  which these applications are viewed by hitting the
+     * menu key, REORDER_LIST message is posted to the handler. this sorts the list
+     * of items based on the sort order.
      */
     private Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             PackageStats ps;
             ApplicationInfo info;
             Bundle data;
-            String pkgName;
-            int idx;
-            int size;
-            boolean chained = false;
+            String pkgName = null;
+            AppInfo appInfo;
             data = msg.getData();
+            if(data != null) {
+                pkgName = data.getString(ATTR_PKG_NAME);
+            }
             switch (msg.what) {
             case COMPUTE_PKG_SIZE_START:
-                mDoneIniting = false;
-                //initialize lists
-                mAppList = new ArrayList<ApplicationInfo>();
-                mSizeMap = new HashMap<String, PackageStats>();
-                mAppAdapterMap = new HashMap<String, Map<String, ?> >();
-                //update application list from PackageManager
-                mAppList = mPm.getInstalledApplications(0);
-                if(mAppList.size() == 0) {
-                    return;
-                }
-                mCurrentPkgIdx = 0;
-                mCurrentPkg = mAppList.get(0);
-                if(localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
-                //register receiver
-                mReceiver = new PackageIntentReceiver();
-                mReceiver.registerReceiver();
-                pkgName = mCurrentPkg.packageName;
-                mObserver = new PkgSizeObserver(0);
-                mObserver.invokeGetSizeInfo(pkgName, true);
+                if(localLOGV) Log.i(TAG, "Message COMPUTE_PKG_SIZE_START");
+                setProgressBarIndeterminateVisibility(true);
+                mComputeIndex = 0;
+                initAppList(mFilterApps);
                 break;
             case COMPUTE_PKG_SIZE_DONE:
-                ps = mObserver.ps;
-                info = mObserver.appInfo;
-                chained = data.getBoolean(ATTR_CHAINED);
-                if(!mObserver.succeeded) {
-                    if(chained) {
-                        removePackageFromAppList(ps.packageName);
-                    } else {
-                        //do not go to adding phase
+                if(localLOGV) Log.i(TAG, "Message COMPUTE_PKG_SIZE_DONE");
+                if(pkgName == null) {
+                     Log.w(TAG, "Ignoring message");
+                     break;
+                }
+                ps = data.getParcelable(ATTR_APP_PKG_STATS);
+                if(ps == null) {
+                    Log.i(TAG, "Invalid package stats for package:"+pkgName);
+                } else {
+                    int pkgId = mAppInfoAdapter.getIndex(pkgName);
+                    if(mComputeIndex != pkgId) {
+                        //spurious call from stale observer
+                        Log.w(TAG, "Stale call back from PkgSizeObserver");
                         break;
                     }
-                } else {
-                    //insert size value
-                    mSizeMap.put(ps.packageName, ps);
-                    Map<String, Object> entry = createMapEntry(mPm.getApplicationLabel(info), 
-                            mPm.getApplicationIcon(info), 
-                            info.loadDescription(mPm), 
-                            getSizeStr(ps));
-                    mAppAdapterMap.put(ps.packageName, entry);
+                    mAppInfoAdapter.updateAppSize(pkgName, ps);
                 }
-                if(chained) {
-                    //here app list is precomputed
-                    idx = data.getInt(ATTR_APP_IDX);
-                    //increment only if succeded
-                    if(mObserver.succeeded) {
-                        idx++;
-                    }
-                    if(idx <  mAppList.size()) {
-                        pkgName = mAppList.get(idx).packageName;
-                        //increment record index and invoke getSizeInfo for next record
-                        mObserver.invokeGetSizeInfo(pkgName, true);
-                    } else {
-                        sortAppList();
-                        createListFromValues();
-                        mDoneIniting = true;
-                    }
+                mComputeIndex++;
+                if (mComputeIndex < mAppInfoAdapter.getCount()) {
+                    // initiate compute package size for next pkg in list
+                    mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(
+                            mComputeIndex), 
+                            COMPUTE_PKG_SIZE_DONE);
                 } else {
-                    //add app info object as well
-                    mAppList.add(info);
-                    sortAppList();
-                    size = mAppList.size();
-                    int i;
-                    for(i = 0; i < size; i++) {
-                        if(mAppList.get(i).packageName.equalsIgnoreCase(mCurrentPkg.packageName)) {
-                            if(i > mCurrentPkgIdx) {
-                                mCurrentPkgIdx = i;
-                            }
-                            break;
+                    // check for added/removed packages
+                    Set<String> keys =  mAddRemoveMap.keySet();
+                    Iterator<String> iter = keys.iterator();
+                    List<String> removeList = new ArrayList<String>();
+                    boolean added = false;
+                    boolean removed = false;
+                    while (iter.hasNext()) {
+                        String key = iter.next();
+                        if (mAddRemoveMap.get(key) == Boolean.TRUE) {
+                            // add
+                            try {
+                                info = mPm.getApplicationInfo(key, 0);
+                                mAppInfoAdapter.addApplicationInfo(info);
+                                added = true;
+                            } catch (NameNotFoundException e) {
+                                Log.w(TAG, "Invalid added package:"+key+" Ignoring entry");
+                            }   
+                        } else {
+                            // remove
+                            removeList.add(key);
+                            removed = true;
                         }
                     }
-                    createListFromValues();
+                    // remove uninstalled packages from list
+                    if (removed) {
+                        mAppInfoAdapter.removeFromList(removeList);
+                    }
+                    // handle newly installed packages
+                    if (added) {
+                        mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(
+                                mComputeIndex), 
+                                COMPUTE_PKG_SIZE_DONE);
+                    } else {
+                        // end computation here
+                        mDoneIniting = true;
+                        mAppInfoAdapter.sortList(mSortOrder);
+                        //load resources now
+                        if(mResourceThread.isAlive()) {
+                            mResourceThread.interrupt();
+                        }
+                        mResourceThread.loadAllResources(mAppInfoAdapter.getAppList());
+                    }
                 }
                 break;
             case REMOVE_PKG:
-                if(!mDoneIniting) {
-                    //insert message again after some delay
-                    sendMessageToHandler(REMOVE_PKG, data, 10*1000);
+                if(localLOGV) Log.i(TAG, "Message REMOVE_PKG");
+                if(pkgName == null) {
+                    Log.w(TAG, "Ignoring message:REMOVE_PKG for null pkgName");
                     break;
                 }
-                pkgName = data.getString(ATTR_PKG_NAME);
-                removePackageFromAppList(pkgName);
-                if(mSizeMap.remove(pkgName) == null) {
-                    Log.i(TAG, "Coudnt remove from size map package:"+pkgName);
-                }
-                if(mAppAdapterMap.remove(pkgName) == null) {
-                    Log.i(TAG, "Coudnt remove from app adapter map package:"+pkgName);
-                }
-                if(mCurrentPkg.packageName.equalsIgnoreCase(pkgName)) {
-                    if(mCurrentPkgIdx == (mAppList.size()-1)) {
-                        mCurrentPkgIdx--;
+                if (!mDoneIniting) {
+                    Boolean currB = mAddRemoveMap.get(pkgName);
+                    if (currB == null || (currB.equals(Boolean.TRUE))) {
+                        mAddRemoveMap.put(pkgName, Boolean.FALSE);
                     }
-                    mCurrentPkg = mAppList.get(mCurrentPkgIdx);
+                    break;
                 }
-                createListFromValues();
+                List<String> pkgList = new ArrayList<String>();
+                pkgList.add(pkgName);
+                mAppInfoAdapter.removeFromList(pkgList);
                 break;
             case REORDER_LIST:
-                int sortOrder = msg.arg1;
-                if(sortOrder != mSortOrder) {
-                    mSortOrder = sortOrder;
-                    if(localLOGV) Log.i(TAG, "Changing sort order to "+mSortOrder);
-                    sortAppList();
-                    mCurrentPkgIdx  = 0;
-                    mCurrentPkg = mAppList.get(mCurrentPkgIdx);
-                    createListFromValues();
+                if(localLOGV) Log.i(TAG, "Message REORDER_LIST");
+                int menuOption = msg.arg1;
+                if((menuOption == SORT_ORDER_ALPHA) || 
+                        (menuOption == SORT_ORDER_SIZE)) {
+                    // Option to sort list
+                    if (menuOption != mSortOrder) {
+                        mSortOrder = menuOption;
+                        if (localLOGV) Log.i(TAG, "Changing sort order to "+mSortOrder);
+                        mAppInfoAdapter.sortList(mSortOrder);
+                    }
+                } else if(menuOption != mFilterApps) {
+                    // Option to filter list
+                    mFilterApps = menuOption;
+                    boolean ret = mAppInfoAdapter.resetAppList(mFilterApps, 
+                            getInstalledApps(mFilterApps));
+                    if(!ret) {
+                        // Reset cache
+                        mAppPropCache = null;
+                        mFilterApps = FILTER_APPS_ALL;
+                        mHandler.sendEmptyMessage(COMPUTE_PKG_SIZE_START);
+                        sendMessageToHandler(REORDER_LIST, menuOption);
+                    }
                 }
                 break;
-            case ADD_PKG:
-                pkgName = data.getString(ATTR_PKG_NAME);
-                if(!mDoneIniting) {
-                   //insert message again after some delay
-                    sendMessageToHandler(ADD_PKG, data, 10*1000);
+            case ADD_PKG_START:
+                if(localLOGV) Log.i(TAG, "Message ADD_PKG_START");
+                if(pkgName == null) {
+                    Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
                     break;
                 }
-                mObserver.invokeGetSizeInfo(pkgName, false);
+                if (!mDoneIniting) {
+                    Boolean currB = mAddRemoveMap.get(pkgName);
+                    if (currB == null || (currB.equals(Boolean.FALSE))) {
+                        mAddRemoveMap.put(pkgName, Boolean.TRUE);
+                    }
+                    break;
+                }
+                try {
+                        info = mPm.getApplicationInfo(pkgName, 0);
+                    } catch (NameNotFoundException e) {
+                        Log.w(TAG, "Couldnt find application info for:"+pkgName);
+                        break;
+                    }
+                mObserver.invokeGetSizeInfo(info, ADD_PKG_DONE);
                 break;
+            case ADD_PKG_DONE:
+                if(localLOGV) Log.i(TAG, "Message COMPUTE_PKG_SIZE_DONE");
+                if(pkgName == null) {
+                    Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
+                    break;
+                }
+                ps = data.getParcelable(ATTR_APP_PKG_STATS);
+                mAppInfoAdapter.addToList(pkgName, ps);
+                break;
+            case REFRESH_ICONS:
+                Map<String, AppInfo> iconMap = (Map<String, AppInfo>) msg.obj;
+                if(iconMap == null) {
+                    Log.w(TAG, "Error loading icons for applications");
+                } else {
+                    mAppInfoAdapter.updateAppsResourceInfo(iconMap);
+                    setProgressBarIndeterminateVisibility(false);
+                }
             default:
                 break;
             }
         }
     };
     
-    private void removePackageFromAppList(String pkgName) {
-        int size = mAppList.size();
-        for(int i = 0; i < size; i++) {
-            if(mAppList.get(i).packageName.equalsIgnoreCase(pkgName)) {
-                mAppList.remove(i);
-                break;
+    List<ApplicationInfo> getInstalledApps(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) {
+                if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                    appList.add(appInfo);
+                }
             }
-        }
-    }
-    
-    private void clearMessages() {
-        synchronized(mHandler) {
-            mHandler.removeMessages(COMPUTE_PKG_SIZE_START);
-            mHandler.removeMessages(COMPUTE_PKG_SIZE_DONE);
-            mHandler.removeMessages(REMOVE_PKG);
-            mHandler.removeMessages(REORDER_LIST);
-            mHandler.removeMessages(ADD_PKG);
-        }
-    }
-    
-    private void sendMessageToHandler(int msgId, Bundle data, long delayMillis) {
-        synchronized(mHandler) {
-            Message msg = mHandler.obtainMessage(msgId);
-            msg.setData(data);
-            if(delayMillis == 0) {
-                mHandler.sendMessage(msg);
-            } else {
-                mHandler.sendMessageDelayed(msg, delayMillis);
+            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 void sendMessageToHandler(int msgId, int arg1) {
-        synchronized(mHandler) {
-            Message msg = mHandler.obtainMessage(msgId);
-            msg.arg1 = arg1;
+    private List<ActivityManager.RunningAppProcessInfo> getRunningAppProcessesList() {
+        ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+        return am.getRunningAppProcesses();
+    }
+    
+    // some initialization code used when kicking off the size computation
+    private void initAppList(int filterOption) {
+        mDoneIniting = false;
+        // Initialize lists
+        List<ApplicationInfo> appList = getInstalledApps(filterOption);
+        mAddRemoveMap = new TreeMap<String, Boolean>();
+        mAppInfoAdapter = new AppInfoAdapter(this, appList);
+        dismissLoadingMsg();
+        // get list and set listeners and adapter
+        ListView lv= (ListView) findViewById(android.R.id.list);
+        lv.setOnItemClickListener(this);
+        lv.setSaveEnabled(true);
+        lv.setItemsCanFocus(true);
+        lv.setOnItemClickListener(this);
+        lv.setAdapter(mAppInfoAdapter);
+        // register receiver
+        mReceiver = new PackageIntentReceiver();
+        mReceiver.registerReceiver();
+        // initiate compute pkg sizes
+        if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
+        mObserver = new PkgSizeObserver();
+        if(appList.size() > 0) {
+            mObserver.invokeGetSizeInfo(appList.get(0), COMPUTE_PKG_SIZE_DONE);
+        } else {
+            mDoneIniting = true;
+        }
+    }
+    
+    // internal structure used to track added and deleted packages when
+    // the activity has focus
+    class AddRemoveInfo {
+        String pkgName;
+        boolean add;
+        public AddRemoveInfo(String pPkgName, boolean pAdd) {
+            pkgName = pPkgName;
+            add = pAdd;
+        }
+    }
+    
+    class ResourceLoaderThread extends Thread {
+        List<ApplicationInfo> mAppList;
+        
+        void loadAllResources(List<ApplicationInfo> appList) {
+            if(appList == null || appList.size() <= 0) {
+                Log.w(TAG, "Empty or null application list");
+                return;
+            }
+            mAppList = appList;
+            start();
+        }
+
+        public void run() {
+            Map<String, AppInfo> iconMap = new HashMap<String, AppInfo>();
+            for (ApplicationInfo appInfo : mAppList) {
+                CharSequence appName = appInfo.loadLabel(mPm);
+                Drawable appIcon = appInfo.loadIcon(mPm);
+                iconMap.put(appInfo.packageName, 
+                        new AppInfo(appInfo.packageName, appName, appIcon));
+            }
+            Message msg = mHandler.obtainMessage(REFRESH_ICONS);
+            msg.obj = iconMap;
             mHandler.sendMessage(msg);
         }
     }
     
-    private void sendMessageToHandler(int msgId) {
-        synchronized(mHandler) {
-            mHandler.sendEmptyMessage(msgId);
+    /* Internal class representing an application or packages displayable attributes
+     * 
+     */
+    class AppInfo {
+        public String pkgName;
+        int index;
+        public  CharSequence appName;
+        public  Drawable appIcon;
+        public CharSequence appSize;
+        public PackageStats appStats;
+        
+        public void refreshIcon(AppInfo pInfo) {
+            appName = pInfo.appName;
+            appIcon = pInfo.appIcon;
+        }
+
+        public AppInfo(String pName, CharSequence aName, Drawable aIcon) {
+            index = -1;
+            pkgName = pName;
+            appName = aName;
+            appIcon = aIcon;
+            appStats = null;
+            appSize = mComputingSizeStr;
+        }
+        
+        public AppInfo(String pName, int pIndex, CharSequence aName, Drawable aIcon, 
+                PackageStats ps) {
+            index = pIndex;
+            pkgName = pName;
+            appName = aName;
+            appIcon = aIcon;
+            if(ps == null) {
+                appSize = mComputingSizeStr;
+            } else {
+                appStats = ps;
+                appSize = getSizeStr();
+            }
+        }
+        public void setSize(PackageStats ps) {
+            appStats = ps;
+            if (ps != null) {
+                appSize = getSizeStr();
+            }
+        }
+        public long getTotalSize() {
+            PackageStats ps = appStats;
+            if (ps != null) {
+                return ps.cacheSize+ps.codeSize+ps.dataSize;
+            }
+            return SIZE_INVALID;
+        }
+        
+        private String getSizeStr() {
+            PackageStats ps = appStats;
+            String retStr = "";
+            // insert total size information into map to display in view
+            // at this point its guaranteed that ps is not null. but checking anyway
+            if (ps != null) {
+                long size = getTotalSize();
+                if (size == SIZE_INVALID) {
+                    return mInvalidSizeStr.toString();
+                }
+                return Formatter.formatFileSize(ManageApplications.this, size);
+            }
+            return retStr;
         }
     }
     
-    class PkgSizeObserver extends IPackageStatsObserver.Stub {
-        public PackageStats ps;
-        public ApplicationInfo appInfo;
-        public Drawable appIcon;
-        public CharSequence appName;
-        public CharSequence appDesc = "";
-        private int mIdx = 0;
-        private boolean mChained = false;
-        public boolean succeeded;
-        PkgSizeObserver(int i) {
-            mIdx = i;
-        }
+    // View Holder used when displaying views
+    static class AppViewHolder {
+        TextView appName;
+        ImageView appIcon;
+        TextView appSize;
+    }
+    
+    /* Custom adapter implementation for the ListView
+     * This adapter maintains a map for each displayed application and its properties
+     * An index value on each AppInfo object indicates the correct position or index
+     * in the list. If the list gets updated dynamically when the user is viewing the list of
+     * applications, we need to return the correct index of position. This is done by mapping
+     * the getId methods via the package name into the internal maps and indices.
+     * The order of applications in the list is mirrored in mAppLocalList
+     */
+    class AppInfoAdapter extends BaseAdapter {
+        private Map<String, AppInfo> mAppPropMap;
+        private List<ApplicationInfo> mAppLocalList;
+        ApplicationInfo.DisplayNameComparator mAlphaComparator;
+        AppInfoComparator mSizeComparator;
         
-        private void getAppDetails() {
-            try {
-                appInfo = mPm.getApplicationInfo(ps.packageName, 0);
-            } catch (NameNotFoundException e) {
-                return;
+        private AppInfo getFromCache(String packageName) {
+            if(mAppPropCache == null) {
+                return null;
             }
-            appName = appInfo.loadLabel(mPm);
-            appIcon = appInfo.loadIcon(mPm);
+            return mAppPropCache.get(packageName);
         }
         
-        public void onGetStatsCompleted(PackageStats pStats, boolean pSucceeded) {
-            Bundle data = new Bundle();
-            ps = pStats;
-            succeeded = pSucceeded;
-            if(mChained) {
-                data.putInt(ATTR_APP_IDX, mIdx);
-                if(succeeded) {
-                    mIdx++;
+        public AppInfoAdapter(Context c, List<ApplicationInfo> appList) {
+            mAppLocalList = appList;
+            boolean useCache = false;
+            int sortOrder = SORT_ORDER_ALPHA;
+            int imax = mAppLocalList.size();
+            if(mAppPropCache != null) {
+                useCache = true;
+                // Activity has been resumed. can use the cache to populate values initially
+                mAppPropMap = mAppPropCache;
+                sortOrder = mSortOrder;
+            }
+            sortAppList(sortOrder);
+            // Recreate property map
+            mAppPropMap = new TreeMap<String, AppInfo>();
+            for (int i = 0; i < imax; i++) {
+                ApplicationInfo info = mAppLocalList.get(i);
+                AppInfo aInfo = getFromCache(info.packageName);
+                if(aInfo == null){
+                    aInfo = new AppInfo(info.packageName, i, 
+                            info.packageName, mDefaultAppIcon, null);   
+                } else {
+                    aInfo.index = i;
+                }
+                mAppPropMap.put(info.packageName, aInfo);
+            }
+        }
+        
+        public int getCount() {
+            return mAppLocalList.size();
+        }
+        
+        public Object getItem(int position) {
+            return mAppLocalList.get(position);
+        }
+        
+        /*
+         * This method returns the index of the package position in the application list
+         */
+        public int getIndex(String pkgName) {
+            if(pkgName == null) {
+                Log.w(TAG, "Getting index of null package in List Adapter");
+            }
+            int imax = mAppLocalList.size();
+            ApplicationInfo appInfo;
+            for(int i = 0; i < imax; i++) {
+                appInfo = mAppLocalList.get(i);
+                if(appInfo.packageName.equalsIgnoreCase(pkgName)) {
+                    return i;
                 }
             }
-            data.putBoolean(ATTR_CHAINED, mChained);
-            getAppDetails();
-            if(localLOGV) Log.i(TAG, "onGetStatsCompleted::"+appInfo.packageName+", ("+ps.cacheSize+","+
-                    ps.codeSize+", "+ps.dataSize);
-            sendMessageToHandler(COMPUTE_PKG_SIZE_DONE, data, 0);
+            return -1;
         }
         
-        public void invokeGetSizeInfo(String packageName, boolean chained) {
-             mChained = chained;
-             mPm.getPackageSizeInfo(packageName, this);
+        public ApplicationInfo getApplicationInfo(int position) {
+            int imax = mAppLocalList.size();
+            if( (position < 0) || (position >= imax)) {
+                Log.w(TAG, "Position out of bounds in List Adapter");
+                return null;
+            }
+            return mAppLocalList.get(position);
+        }
+        
+        public void addApplicationInfo(ApplicationInfo info) {
+            if(info == null) {
+                Log.w(TAG, "Ignoring null add in List Adapter");
+                return;
+            }
+            mAppLocalList.add(info);
+        }
+
+        public long getItemId(int position) {
+            int imax = mAppLocalList.size();
+            if( (position < 0) || (position >= imax)) {
+                Log.w(TAG, "Position out of bounds in List Adapter");
+                return -1;
+            }
+            return mAppPropMap.get(mAppLocalList.get(position).packageName).index;
+        }
+        
+        public List<ApplicationInfo> getAppList() {
+            return mAppLocalList;
+        }
+        
+        public View getView(int position, View convertView, ViewGroup parent) {
+            // A ViewHolder keeps references to children views to avoid unneccessary calls
+            // to findViewById() on each row.
+            AppViewHolder holder;
+
+            // When convertView is not null, we can reuse it directly, there is no need
+            // to reinflate it. We only inflate a new View when the convertView supplied
+            // by ListView is null.
+            if (convertView == null) {
+                convertView = mInflater.inflate(R.layout.manage_applications_item, null);
+
+                // Creates a ViewHolder and store references to the two children views
+                // we want to bind data to.
+                holder = new AppViewHolder();
+                holder.appName = (TextView) convertView.findViewById(R.id.app_name);
+                holder.appIcon = (ImageView) convertView.findViewById(R.id.app_icon);
+                holder.appSize = (TextView) convertView.findViewById(R.id.app_size);
+                convertView.setTag(holder);
+            } else {
+                // Get the ViewHolder back to get fast access to the TextView
+                // and the ImageView.
+                holder = (AppViewHolder) convertView.getTag();
+            }
+
+            // Bind the data efficiently with the holder
+            ApplicationInfo appInfo = mAppLocalList.get(position);
+            AppInfo mInfo = mAppPropMap.get(appInfo.packageName);
+            if(mInfo != null) {
+                if(mInfo.appName != null) {
+                    holder.appName.setText(mInfo.appName);
+                }
+                if(mInfo.appIcon != null) {
+                    holder.appIcon.setImageDrawable(mInfo.appIcon);
+                }
+                holder.appSize.setText(mInfo.appSize);
+            } else {
+                Log.w(TAG, "No info for package:"+appInfo.packageName+" in property map");
+            }
+            return convertView;
+        }
+        
+        private void adjustIndex() {
+            int imax = mAppLocalList.size();
+            ApplicationInfo info;
+            for (int i = 0; i < imax; i++) {
+                info = mAppLocalList.get(i);
+                mAppPropMap.get(info.packageName).index = i;
+            }
+        }
+        
+        public void sortAppList(int sortOrder) {
+            Collections.sort(mAppLocalList, getAppComparator(sortOrder));
+        }
+        
+        public void sortList(int sortOrder) {
+            sortAppList(sortOrder);
+            adjustIndex();
+            notifyDataSetChanged();
+        }
+        
+        public boolean resetAppList(int filterOption, List<ApplicationInfo> appList) {
+           // Create application list based on the filter value
+           mAppLocalList = appList;
+           // Check for all properties in map before sorting. Populate values from cache
+           for(ApplicationInfo applicationInfo : mAppLocalList) {
+               AppInfo appInfo = mAppPropMap.get(applicationInfo.packageName);
+               if(appInfo == null) {
+                   AppInfo rInfo = getFromCache(applicationInfo.packageName);
+                   if(rInfo == null) {
+                       // Need to load resources again. Inconsistency somewhere
+                       return false;
+                   }
+                   mAppPropMap.put(applicationInfo.packageName, rInfo);
+               }
+           }
+           sortList(mSortOrder);
+           return true;
+        }
+        
+        private Comparator<ApplicationInfo> getAppComparator(int sortOrder) {
+            if (sortOrder == SORT_ORDER_ALPHA) {
+                // Lazy initialization
+                if (mAlphaComparator == null) {
+                    mAlphaComparator = new ApplicationInfo.DisplayNameComparator(mPm);
+                }
+                return mAlphaComparator;
+            }
+            // Lazy initialization
+            if(mSizeComparator == null) {
+                mSizeComparator = new AppInfoComparator(mAppPropMap);
+            }
+            return mSizeComparator;
+        }
+        
+        public void updateAppsResourceInfo(Map<String, AppInfo> iconMap) {
+            if(iconMap == null) {
+                Log.w(TAG, "Null iconMap when refreshing icon in List Adapter");
+                return;
+            }
+            boolean changed = false;
+            for (ApplicationInfo info : mAppLocalList) {
+                AppInfo pInfo = iconMap.get(info.packageName);
+                if(pInfo != null) {
+                    AppInfo aInfo = mAppPropMap.get(info.packageName);
+                    aInfo.refreshIcon(pInfo);
+                    changed = true;
+                }
+            }
+            if(changed) {
+                notifyDataSetChanged();
+            }
+        }
+        
+        public void addToList(String pkgName, PackageStats ps) {
+            if(pkgName == null) {
+                Log.w(TAG, "Adding null pkg to List Adapter");
+                return;
+            }
+            ApplicationInfo info;
+            try {
+                info = mPm.getApplicationInfo(pkgName, 0);
+            } catch (NameNotFoundException e) {
+                Log.w(TAG, "Ignoring non-existent package:"+pkgName);
+                return;
+            }
+            if(info == null) {
+                // Nothing to do log error message and return
+                Log.i(TAG, "Null ApplicationInfo for package:"+pkgName);
+                return;
+            }
+            // Binary search returns a negative index (ie --index) of the position where
+            // this might be inserted. 
+            int newIdx = Collections.binarySearch(mAppLocalList, info, 
+                    getAppComparator(mSortOrder));
+            if(newIdx >= 0) {
+                Log.i(TAG, "Strange. Package:"+pkgName+" is not new");
+                return;
+            }
+            // New entry
+            newIdx = -newIdx-1;
+            mAppLocalList.add(newIdx, info);
+            mAppPropMap.put(info.packageName, new AppInfo(pkgName, newIdx,
+                    info.loadLabel(mPm), info.loadIcon(mPm), ps));
+            adjustIndex();
+            notifyDataSetChanged();
+        }
+        
+        public void removeFromList(List<String> pkgNames) {
+            if(pkgNames == null) {
+                Log.w(TAG, "Removing null pkg list from List Adapter");
+                return;
+            }
+            int imax = mAppLocalList.size();
+            boolean found = false;
+            ApplicationInfo info;
+            int i, k;
+            String pkgName;
+            int kmax = pkgNames.size();
+            if(kmax  <= 0) {
+                Log.w(TAG, "Removing empty pkg list from List Adapter");
+                return;
+            }
+            int idxArr[] = new int[kmax];
+            for (k = 0; k < kmax; k++) {
+                idxArr[k] = -1;
+            }
+            for (i = 0; i < imax; i++) {
+                info = mAppLocalList.get(i);
+                for (k = 0; k < kmax; k++) {
+                    pkgName = pkgNames.get(k);
+                    if (info.packageName.equalsIgnoreCase(pkgName)) {
+                        idxArr[k] = i;
+                        found = true;
+                        break;
+                    }
+                }
+            }
+            // Sort idxArr
+            Arrays.sort(idxArr);
+            // remove the packages based on decending indices
+            for (k = kmax-1; k >= 0; k--) {
+                // Check if package has been found in the list of existing apps first
+                if(idxArr[k] == -1) {
+                    break;
+                }
+                info = mAppLocalList.get(idxArr[k]);
+                mAppLocalList.remove(idxArr[k]);
+                mAppPropMap.remove(info.packageName);
+                if (localLOGV) Log.i(TAG, "Removed pkg:"+info.packageName+ " list");
+            }
+            if (found) {
+                adjustIndex();
+                notifyDataSetChanged();
+            }
+        }   
+        
+        public void updateAppSize(String pkgName, PackageStats ps) {
+            if(pkgName == null) {
+                return;
+            }
+            AppInfo entry = mAppPropMap.get(pkgName);
+            if (entry == null) {
+                Log.w(TAG, "Entry for package:"+pkgName+"doesnt exist in map");
+                return;
+            }
+            // Copy the index into the newly updated entry
+            entry.setSize(ps);
+            notifyDataSetChanged();
+        }
+
+        public PackageStats getAppStats(String pkgName) {
+            if(pkgName == null) {
+                return null;
+            }
+            AppInfo entry = mAppPropMap.get(pkgName);
+            if (entry == null) {
+                return null;
+            }
+            return entry.appStats;
+        }
+    }
+    
+    /*
+     * Utility method to clear messages to Handler
+     * We need'nt synchronize on the Handler since posting messages is guaranteed
+     * to be thread safe. Even if the other thread that retrieves package sizes
+     * posts a message, we do a cursory check of validity on mAppInfoAdapter's applist
+     */
+    private void clearMessagesInHandler() {
+        mHandler.removeMessages(COMPUTE_PKG_SIZE_START);
+        mHandler.removeMessages(COMPUTE_PKG_SIZE_DONE);
+        mHandler.removeMessages(REMOVE_PKG);
+        mHandler.removeMessages(REORDER_LIST);
+        mHandler.removeMessages(ADD_PKG_START);
+        mHandler.removeMessages(ADD_PKG_DONE);
+    }
+    
+    private void sendMessageToHandler(int msgId, int arg1) {
+        Message msg = mHandler.obtainMessage(msgId);
+        msg.arg1 = arg1;
+        mHandler.sendMessage(msg);
+    }
+    
+    private void sendMessageToHandler(int msgId, Bundle data) {
+        Message msg = mHandler.obtainMessage(msgId);
+        msg.setData(data);
+        mHandler.sendMessage(msg);
+    }
+    
+    private void sendMessageToHandler(int msgId) {
+        mHandler.sendEmptyMessage(msgId);
+    }
+    
+    /*
+     * Stats Observer class used to compute package sizes and retrieve size information
+     * PkgSizeOberver is the call back thats used when invoking getPackageSizeInfo on
+     * PackageManager. The values in call back onGetStatsCompleted are validated
+     * and the specified message is passed to mHandler. The package name
+     * and the AppInfo object corresponding to the package name are set on the message
+     */
+    class PkgSizeObserver extends IPackageStatsObserver.Stub {
+        private ApplicationInfo mAppInfo;
+        private int mMsgId; 
+        public void onGetStatsCompleted(PackageStats pStats, boolean pSucceeded) {
+            if(DEBUG_PKG_DELAY) {
+                try {
+                    Thread.sleep(10*1000);
+                } catch (InterruptedException e) {
+                }
+            }
+            AppInfo appInfo = null;
+            Bundle data = new Bundle();
+            data.putString(ATTR_PKG_NAME, mAppInfo.packageName);
+            if(pSucceeded && pStats != null) {
+                if (localLOGV) Log.i(TAG, "onGetStatsCompleted::"+pStats.packageName+", ("+
+                        pStats.cacheSize+","+
+                        pStats.codeSize+", "+pStats.dataSize);
+                data.putParcelable(ATTR_APP_PKG_STATS, pStats);
+            } else {
+                Log.w(TAG, "Invalid package stats from PackageManager");
+            }
+            //post message to Handler
+            Message msg = mHandler.obtainMessage(mMsgId, data);
+            msg.setData(data);
+            mHandler.sendMessage(msg);
+        }
+
+        public void invokeGetSizeInfo(ApplicationInfo pAppInfo, int msgId) {
+            if(pAppInfo == null || pAppInfo.packageName == null) {
+                return;
+            }
+            if(localLOGV) Log.i(TAG, "Invoking getPackageSizeInfo for package:"+
+                    pAppInfo.packageName);
+            mMsgId = msgId;
+            mAppInfo = pAppInfo;
+            mPm.getPackageSizeInfo(pAppInfo.packageName, this);
         }
     }
     
@@ -360,239 +998,147 @@
             String actionStr = intent.getAction();
             Uri data = intent.getData();
             String pkgName = data.getEncodedSchemeSpecificPart();
-            if(localLOGV) Log.i(TAG, "action:"+actionStr+", for package:"+pkgName);
+            if (localLOGV) Log.i(TAG, "action:"+actionStr+", for package:"+pkgName);
             updatePackageList(actionStr, pkgName);
         }
     }
     
     private void updatePackageList(String actionStr, 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)) {
+        // 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, data, 0);
-        } else if(Intent.ACTION_PACKAGE_REMOVED.equalsIgnoreCase(actionStr)) {
+            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, 0);
-        } else if(Intent.ACTION_PACKAGE_CHANGED.equalsIgnoreCase(actionStr)) {
-            //force adapter to draw the list again. TODO derive from SimpleAdapter
-            //to avoid this
-           
-        }   
-    }
-    
-    /*
-     * Utility method to create an array of map objects from a map of map objects
-     *  for displaying list items to be used in SimpleAdapter.
-     */
-    private void createListFromValues() {
-        findViewById(R.id.center_text).setVisibility(View.GONE);
-        populateAdapterList();
-        mAppAdapter.setViewBinder(this);
-        ListView lv= (ListView) findViewById(android.R.id.list);
-        lv.setOnItemClickListener(this);
-        lv.setAdapter(mAppAdapter);
-        if(mCurrentPkgIdx != -1) {
-            lv.setSelection(mCurrentPkgIdx);
+            sendMessageToHandler(REMOVE_PKG, data);
         }
     }
     
+    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        String action = getIntent().getAction();
-        if(action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
+        Intent lIntent = getIntent();
+        String action = lIntent.getAction();
+        if (action.equals(Intent.ACTION_MANAGE_PACKAGE_STORAGE)) {
             mSortOrder = SORT_ORDER_SIZE;
         }
         mPm = getPackageManager();
-        //load strings from resources
-        mBStr = getString(R.string.b_text);
-        mKbStr = getString(R.string.kb_text);
-        mMbStr = getString(R.string.mb_text);
+        // initialize some window features
+        requestWindowFeature(Window.FEATURE_RIGHT_ICON);
+        requestWindowFeature(Window.FEATURE_PROGRESS);
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+        // init mLoadingDlg
+        mLoadingDlg = new ProgressDialog(this);
+        mLoadingDlg.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+        mLoadingDlg.setMessage(getText(R.string.loading));
+        mLoadingDlg.setIndeterminate(true);        
+        mLoadingDlg.setOnCancelListener(this);
+        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);
+    }
+    
+    private void showLoadingMsg() {
+        if (mLoadingDlg != null) {
+            if(localLOGV) Log.i(TAG, "Displaying Loading message");
+            mLoadingDlg.show();
+        }
+    }
+    
+    private void dismissLoadingMsg() {
+        if ((mLoadingDlg != null) && (mLoadingDlg.isShowing())) {
+            if(localLOGV) Log.i(TAG, "Dismissing Loading message");
+            mLoadingDlg.dismiss();
+        }
     }
     
     @Override
     public void onStart() {
         super.onStart();
         setContentView(R.layout.compute_sizes);
-        //clear all messages related to application list
-        clearMessages();
+        showLoadingMsg();
+        // Create a thread to load resources
+        mResourceThread = new ResourceLoaderThread();
         sendMessageToHandler(COMPUTE_PKG_SIZE_START);
     }
 
     @Override
     public void onStop() {
         super.onStop();
-        //register receiver here
+        // clear all messages related to application list
+        clearMessagesInHandler();
+        // register receiver here
         unregisterReceiver(mReceiver);        
+        mAppPropCache = mAppInfoAdapter.mAppPropMap;
     }
     
+    /*
+     * comparator class used to sort AppInfo objects based on size
+     */
     public static class AppInfoComparator implements Comparator<ApplicationInfo> {
-        public AppInfoComparator(HashMap<String, PackageStats> pSizeMap) {
-            mSizeMap= pSizeMap;
+        public AppInfoComparator(Map<String, AppInfo> pAppPropMap) {
+            mAppPropMap= pAppPropMap;
         }
 
         public final int compare(ApplicationInfo a, ApplicationInfo b) {
-            PackageStats aps, bps;
-            aps = mSizeMap.get(a.packageName);
-            bps = mSizeMap.get(b.packageName);
-            if (aps == null && bps == null) {
-                return 0;
-            } else if (aps == null) {
-                return 1;
-            } else if (bps == null) {
-                return -1;
-            }
-            long atotal = aps.dataSize+aps.codeSize+aps.cacheSize;
-            long btotal = bps.dataSize+bps.codeSize+bps.cacheSize;
-            long ret = atotal-btotal;
-            //negate result to sort in descending order
-            if(ret < 0) {
+            AppInfo ainfo = mAppPropMap.get(a.packageName);
+            AppInfo binfo = mAppPropMap.get(b.packageName);
+            long atotal = ainfo.getTotalSize();
+            long btotal = binfo.getTotalSize();
+            long ret = atotal - btotal;
+            // negate result to sort in descending order
+            if (ret < 0) {
                 return 1;
             }
-            if(ret == 0) {
+            if (ret == 0) {
                 return 0;
             }
             return -1;
         }
-        private HashMap<String, PackageStats> mSizeMap;
+        private Map<String, AppInfo> mAppPropMap;
     }
-
-    /*
-     * Have to extract elements form map and populate a list ot be used by
-     * SimpleAdapter when displaying list elements. The sort order has to follow
-     * the order of elements in mAppList.
-     */
-     private List<Map<String, ?>> createAdapterListFromMap() {
-         //get the index from mAppInfo which gives the correct sort position
-         int imax = mAppList.size();
-         if(localLOGV) Log.i(TAG, "Creating new adapter list");
-         List<Map<String, ?>> adapterList = new ArrayList<Map<String, ?>>();
-         ApplicationInfo tmpInfo;
-         for(int i = 0; i < imax; i++) {
-             tmpInfo = mAppList.get(i);
-             Map<String, Object>newObj = new TreeMap<String, Object>(
-                     mAppAdapterMap.get(tmpInfo.packageName));
-             adapterList.add(newObj);
-         }
-         return adapterList;
-     }
      
-    private void populateAdapterList() {
-        mAppAdapter = new SimpleAdapter(this, createAdapterListFromMap(),
-                    R.layout.manage_applications_item, sKeys, sResourceIds);
-    }
-    
-    private String getSizeStr(PackageStats ps) {
-        String retStr = "";
-        //insert total size information into map to display in view
-        //at this point its guaranteed that ps is not null. but checking anyway
-        if(ps != null) {
-            long size = ps.cacheSize+ps.codeSize+ps.dataSize;
-            if(size < 1024) {
-                return String.valueOf(size)+mBStr;
-            }
-            long kb, mb, rem;
-            kb = size >> 10;
-            rem = size - (kb << 10);
-            if(kb < 1024) {
-                if(rem > 512) {
-                    kb++;
-                }
-                retStr += String.valueOf(kb)+mKbStr;
-                return retStr;
-            }
-            mb = kb >> 10;
-            if(kb >= 512) {
-                //round off
-                mb++;
-            }
-            retStr += String.valueOf(mb)+ mMbStr;
-            return retStr;
-        } else {
-            Log.w(TAG, "Something fishy, cannot find size info for package:"+ps.packageName);
-        }
-        return retStr;
-    }
-    
-    public void sortAppList() {
-        // Sort application list
-        if(mSortOrder == SORT_ORDER_ALPHA) {
-            Collections.sort(mAppList, new ApplicationInfo.DisplayNameComparator(mPm));
-        } else if(mSortOrder == SORT_ORDER_SIZE) {
-            Collections.sort(mAppList, new AppInfoComparator(mSizeMap));
-        }
-    }
-    
-    private Map<String, Object> createMapEntry(CharSequence appName, 
-            Drawable appIcon, CharSequence appDesc, String sizeStr) {
-        Map<String, Object> map = new TreeMap<String, Object>();
-        map.put(KEY_APP_NAME, appName);
-        //the icon cannot be null. if the application hasnt set it, the default icon is returned.
-        map.put(KEY_APP_ICON, appIcon);
-        if(appDesc == null) {
-            appDesc="";
-        }
-        map.put(KEY_APP_DESC, appDesc);
-        map.put(KEY_APP_SIZE, sizeStr);
-        return map;
-    }
-    
+    // utility method used to start sub activity
     private void startApplicationDetailsActivity(ApplicationInfo info, PackageStats ps) {
-        //Create intent to start new activity
+        // Create intent to start new activity
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(this, InstalledAppDetails.class);
-        intent.putExtra(APP_PKG_NAME, info.packageName);
-        if(localLOGV) Log.i(TAG, "code="+ps.codeSize+", cache="+ps.cacheSize+", data="+ps.dataSize);
-        intent.putExtra(APP_PKG_SIZE,  ps);
-        if(localLOGV) Log.i(TAG, "Starting sub activity to display info for app:"+info
-                +" with intent:"+intent);
-        //start new activity to display extended information
-        if ((info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-        }
+        mCurrentPkgName = info.packageName;
+        intent.putExtra(APP_PKG_NAME, mCurrentPkgName);
+        intent.putExtra(APP_PKG_SIZE, ps);
+        // start new activity to display extended information
         startActivityForResult(intent, INSTALLED_APP_DETAILS);
     }
     
-    public boolean setViewValue(View view, Object data, String textRepresentation) {
-        if(data == null) {
-            return false;
-        }
-        int id = view.getId();
-        switch(id) {
-        case R.id.app_name:
-            ((TextView)view).setText((String)data);
-            break;
-        case R.id.app_icon:
-            ((ImageView)view).setImageDrawable((Drawable)data);
-            break;
-        case R.id.app_description:
-            ((TextView)view).setText((String)data);
-            break;
-        case R.id.app_size:
-            ((TextView)view).setText((String)data);
-            break;
-        default:
-                break;
-        }
-        return true;
-    }
-    
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add(0, SORT_ORDER_ALPHA, 0, R.string.sort_order_alpha)
+        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, 0, R.string.sort_order_size)
-                .setIcon(android.R.drawable.ic_menu_sort_by_size);
+        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_APPS_ALL, 3, R.string.filter_apps_all);
+        menu.add(0, FILTER_APPS_RUNNING, 4, R.string.filter_apps_running);
+        menu.add(0, FILTER_APPS_THIRD_PARTY, 5, R.string.filter_apps_third_party);        
         return true;
     }
     
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        if(mDoneIniting) {
+        if (mDoneIniting) {
             menu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
-            menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder!= SORT_ORDER_SIZE);
+            menu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
+            menu.findItem(FILTER_APPS_ALL).setVisible(mFilterApps != FILTER_APPS_ALL);
+            menu.findItem(FILTER_APPS_THIRD_PARTY).setVisible(
+                    mFilterApps != FILTER_APPS_THIRD_PARTY);
+            menu.findItem(FILTER_APPS_RUNNING).setVisible(
+                    mFilterApps != FILTER_APPS_RUNNING);
             return true;
         } 
         return false;
@@ -607,10 +1153,13 @@
 
     public void onItemClick(AdapterView<?> parent, View view, int position,
             long id) {
-        mCurrentPkgIdx=position;
-        ApplicationInfo info = mAppList.get(position);
-        mCurrentPkg = info;        
-        PackageStats ps = mSizeMap.get(info.packageName);
-        startApplicationDetailsActivity(info, ps);
+        ApplicationInfo info = (ApplicationInfo)mAppInfoAdapter.getItem(position);
+        startApplicationDetailsActivity(info, mAppInfoAdapter.getAppStats(info.packageName));
+    }
+    
+    // onCancel call back for dialog thats displayed when data is being loaded
+    public void onCancel(DialogInterface dialog) {
+        mLoadingDlg = null;
+        finish();
     }
 }