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
This commit is contained in:
Jeff Brown
2010-03-29 17:51:23 -07:00
parent 316c0db4eb
commit 347c9a0544

View File

@@ -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) {