Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 347c9a05 authored by Jeff Brown's avatar Jeff Brown
Browse files

Refresh apps when they become (un)available.

This fixes a bug in the current code that causes apps to be removed
from the list when they become unavailable.

Change-Id: Ic0b4c0fa34662ce3c458117b6807742448ec6575
parent 316c0db4
Loading
Loading
Loading
Loading
+65 −56
Original line number Diff line number Diff line
@@ -81,22 +81,26 @@ import java.util.concurrent.CountDownLatch;
 * 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 
 * 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.
 */
@@ -173,7 +177,7 @@ public class ManageApplications extends TabActivity implements
    private PackageIntentReceiver mReceiver;
    // atomic variable used to track if computing pkg sizes is in progress. should be volatile?
    
    private boolean mComputeSizes = false;
    private boolean mComputeSizesFinished = false;
    // default icon thats used when displaying applications initially before resource info is
    // retrieved
    private static Drawable mDefaultAppIcon;
@@ -212,7 +216,7 @@ public class ManageApplications extends TabActivity implements
    private AppInfoCache mCache = new AppInfoCache();
    
    // Boolean variables indicating state
    private boolean mLoadLabels = false;
    private boolean mLoadLabelsFinished = false;
    private boolean mSizesFirst = false;
    // ListView used to display list
    private ListView mListView;
@@ -224,30 +228,35 @@ public class ManageApplications extends TabActivity implements
    private boolean mSetListViewLater = true;
    
    /*
     * Handler class to handle messages for various operations
     * 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
     * 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
     * label, description, icon etc., are 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
     * 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
@@ -293,7 +302,7 @@ public class ManageApplications extends TabActivity implements
                mAppInfoAdapter.bulkUpdateSizes(pkgs, sizes, formatted);
                break;
            case COMPUTE_END:
                mComputeSizes = true;
                mComputeSizesFinished = true;
                mFirst = true;
                mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
                break;
@@ -303,7 +312,7 @@ public class ManageApplications extends TabActivity implements
                    Log.w(TAG, "Ignoring message:REMOVE_PKG for null pkgName");
                    break;
                }
                if (!mComputeSizes) {
                if (!mComputeSizesFinished) {
                    Boolean currB = mAddRemoveMap.get(pkgName);
                    if (currB == null || (currB.equals(Boolean.TRUE))) {
                        mAddRemoveMap.put(pkgName, Boolean.FALSE);
@@ -343,7 +352,7 @@ public class ManageApplications extends TabActivity implements
                    Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName");
                    break;
                }
                if (!mComputeSizes || !mLoadLabels) {
                if (!mComputeSizesFinished || !mLoadLabelsFinished) {
                    Boolean currB = mAddRemoveMap.get(pkgName);
                    if (currB == null || (currB.equals(Boolean.FALSE))) {
                        mAddRemoveMap.put(pkgName, Boolean.TRUE);
@@ -388,7 +397,7 @@ public class ManageApplications extends TabActivity implements
                }
                break;
            case REFRESH_DONE:
                mLoadLabels = true;
                mLoadLabelsFinished = true;
                mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
                break;
            case NEXT_LOAD_STEP:
@@ -398,7 +407,7 @@ public class ManageApplications extends TabActivity implements
                    mSetListViewLater = false;
                    mFirst = true;
                }
                if (mComputeSizes && mLoadLabels) {
                if (mComputeSizesFinished && mLoadLabelsFinished) {
                    doneLoadingData();
                    // Check for added/removed packages
                    Set<String> keys =  mAddRemoveMap.keySet();
@@ -412,7 +421,7 @@ public class ManageApplications extends TabActivity implements
                        }
                    }
                    mAddRemoveMap.clear();
                } else if (!mComputeSizes && !mLoadLabels) {
                } else if (!mComputeSizesFinished && !mLoadLabelsFinished) {
                     // Either load the package labels or initiate get size info
                    if (mSizesFirst) {
                        initComputeSizes();
@@ -425,9 +434,9 @@ public class ManageApplications extends TabActivity implements
                        initListView();
                        mSetListViewLater = false;
                    }
                    if (!mComputeSizes) {
                    if (!mComputeSizesFinished) {
                        initComputeSizes();
                    } else if (!mLoadLabels) {
                    } else if (!mLoadLabelsFinished) {
                        initResourceThread();
                    }
                }
@@ -762,8 +771,8 @@ public class ManageApplications extends TabActivity implements
     // Some initialization code used when kicking off the size computation
    private void initAppList(List<ApplicationInfo> appList, int filterOption) {
        setProgressBarIndeterminateVisibility(true);
        mComputeSizes = false;
        mLoadLabels = false;
        mComputeSizesFinished = false;
        mLoadLabelsFinished = false;
        // Initialize lists
        mAddRemoveMap = new TreeMap<String, Boolean>();
        mAppInfoAdapter.initMapFromList(appList, filterOption);
@@ -791,7 +800,7 @@ public class ManageApplications extends TabActivity implements
        if ((appList != null) && (appList.size()) > 0) {
            mSizeComputor = new TaskRunner(appList);
        } else {
            mComputeSizes = true;
            mComputeSizesFinished = true;
        }
    }
    
@@ -1107,7 +1116,7 @@ public class ManageApplications extends TabActivity implements
                Log.w(TAG, "Invalid view position:"+position+", actual size is:"+mAppLocalList.size());
                return null;
            }
            // A ViewHolder keeps references to children views to avoid unneccessary calls
            // A ViewHolder keeps references to children views to avoid unnecessary calls
            // to findViewById() on each row.
            AppViewHolder holder;

@@ -1563,8 +1572,6 @@ public class ManageApplications extends TabActivity implements
         }
         @Override
         public void onReceive(Context context, Intent intent) {
             // technically we dont have to invoke handler since onReceive is invoked on
             // the main thread but doing it here for better clarity
             String actionStr = intent.getAction();
             if (Intent.ACTION_PACKAGE_ADDED.equals(actionStr) ||
                     Intent.ACTION_PACKAGE_REMOVED.equals(actionStr)) {
@@ -1573,24 +1580,26 @@ public class ManageApplications extends TabActivity implements
                 updatePackageList(actionStr, pkgName);
             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr) ||
                     Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(actionStr)) {
                 boolean available = Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr);
                 // When applications become available or unavailable (perhaps because
                 // the SD card was inserted or ejected) we need to refresh the
                 // AppInfo with new label, icon and size information as appropriate
                 // given the newfound (un)availability of the application.
                 // A simple way to do that is to treat the refresh as a package
                 // removal followed by a package addition.
                 String pkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                 if (pkgList == null || pkgList.length == 0) {
                     // Ignore
                     return;
                 }
                 String msg = available ? Intent.ACTION_PACKAGE_ADDED :
                     Intent.ACTION_PACKAGE_REMOVED;
                 for (String pkgName : pkgList) {
                     updatePackageList(msg, pkgName);
                     updatePackageList(Intent.ACTION_PACKAGE_REMOVED, pkgName);
                     updatePackageList(Intent.ACTION_PACKAGE_ADDED, 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)) {
            Bundle data = new Bundle();
            data.putString(ATTR_PKG_NAME, pkgName);
@@ -1640,7 +1649,7 @@ public class ManageApplications extends TabActivity implements
        mReceiver = new PackageIntentReceiver();
        mObserver = new PkgSizeObserver();
        // Create adapter and list view here
        List<ApplicationInfo> appList = getInstalledApps(mSortOrder);
        List<ApplicationInfo> appList = getInstalledApps(FILTER_APPS_ALL);
        mAppInfoAdapter = new AppInfoAdapter(this, appList);
        ListView lv = (ListView) mRootView.findViewById(android.R.id.list);
        lv.setOnItemClickListener(this);
@@ -1776,7 +1785,7 @@ public class ManageApplications extends TabActivity implements
                        err = true;
                        break;
                    }
                    // Buffer length cannot be great then max.
                    // Buffer length cannot be greater than max.
                    fis.read(byteBuff, 0, buffLen);
                    String buffStr = new String(byteBuff);
                    if (DEBUG_CACHE) {