summaryrefslogtreecommitdiffstats
path: root/src/com/android/settings/ManageApplications.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/settings/ManageApplications.java')
-rw-r--r--src/com/android/settings/ManageApplications.java1278
1 files changed, 0 insertions, 1278 deletions
diff --git a/src/com/android/settings/ManageApplications.java b/src/com/android/settings/ManageApplications.java
deleted file mode 100644
index 512e547..0000000
--- a/src/com/android/settings/ManageApplications.java
+++ /dev/null
@@ -1,1278 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import com.android.settings.R;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-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;
-import android.content.pm.IPackageStatsObserver;
-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.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 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.
- * This activity passes the package name and size information to the
- * InstalledAppDetailsActivity to avoid recomputation of the package size information.
- */
-public class ManageApplications extends ListActivity implements
- OnItemClickListener, DialogInterface.OnCancelListener,
- DialogInterface.OnClickListener {
- // TAG for this activity
- private static final String TAG = "ManageApplications";
-
- // log information boolean
- private boolean localLOGV = Config.LOGV || false;
-
- // 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;
- public static final int FILTER_OPTIONS = MENU_OPTIONS_BASE + 5;
- // Alert Dialog presented to user to find out the filter option
- AlertDialog.Builder mAlertDlgBuilder;
- // 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 INIT_PKG_INFO = 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;
- private static final int NEXT_LOAD_STEP = HANDLER_MESSAGE_BASE+8;
-
- // 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 mComputeSizes = false;
- // 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;
-
- // empty message displayed when list is empty
- private TextView mEmptyView;
-
- // Boolean variables indicating state
- private boolean mLoadLabels = false;
- private boolean mSizesFirst = false;
-
- /*
- * 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 = null;
- AppInfo appInfo;
- data = msg.getData();
- if(data != null) {
- pkgName = data.getString(ATTR_PKG_NAME);
- }
- switch (msg.what) {
- case INIT_PKG_INFO:
- if(localLOGV) Log.i(TAG, "Message INIT_PKG_INFO");
- setProgressBarIndeterminateVisibility(true);
- mComputeIndex = 0;
- // Retrieve the package list and init some structures
- initAppList(mFilterApps);
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- break;
- case COMPUTE_PKG_SIZE_DONE:
- 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;
- }
- mAppInfoAdapter.updateAppSize(pkgName, ps);
- }
- mComputeIndex++;
- if (mComputeIndex < mAppInfoAdapter.getCount()) {
- // initiate compute package size for next pkg in list
- mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(
- mComputeIndex),
- COMPUTE_PKG_SIZE_DONE);
- } else {
- // 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;
- }
- }
- // 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
- mComputeSizes = true;
- mAppInfoAdapter.sortList(mSortOrder);
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- }
- }
- break;
- case REMOVE_PKG:
- if(localLOGV) Log.i(TAG, "Message REMOVE_PKG");
- if(pkgName == null) {
- Log.w(TAG, "Ignoring message:REMOVE_PKG for null pkgName");
- break;
- }
- if (!mComputeSizes) {
- Boolean currB = mAddRemoveMap.get(pkgName);
- if (currB == null || (currB.equals(Boolean.TRUE))) {
- mAddRemoveMap.put(pkgName, Boolean.FALSE);
- }
- break;
- }
- List<String> pkgList = new ArrayList<String>();
- pkgList.add(pkgName);
- mAppInfoAdapter.removeFromList(pkgList);
- break;
- case REORDER_LIST:
- 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(INIT_PKG_INFO);
- sendMessageToHandler(REORDER_LIST, menuOption);
- }
- }
- break;
- 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;
- }
- if (!mComputeSizes) {
- 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);
- }
- mLoadLabels = true;
- mHandler.sendEmptyMessage(NEXT_LOAD_STEP);
- break;
- case NEXT_LOAD_STEP:
- if (mComputeSizes && mLoadLabels) {
- doneLoadingData();
- } else if (!mComputeSizes && !mLoadLabels) {
- // Either load the package labels or initiate get size info
- if (mSizesFirst) {
- initComputeSizes();
- } else {
- initResourceThread();
- }
- } else {
- // Create list view from the adapter here. Wait till the sort order
- // of list is defined. its either by label or by size. so atleast one of the
- // first steps should be complete before creating the list
- createListView();
- if (!mComputeSizes) {
- initComputeSizes();
- } else if (!mLoadLabels) {
- initResourceThread();
- }
- }
- break;
- default:
- break;
- }
- }
- };
-
- private void doneLoadingData() {
- setProgressBarIndeterminateVisibility(false);
- }
-
- 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) {
- 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 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) {
- mComputeSizes = false;
- // Initialize lists
- List<ApplicationInfo> appList = getInstalledApps(filterOption);
- mAddRemoveMap = new TreeMap<String, Boolean>();
- mAppInfoAdapter = new AppInfoAdapter(this, appList);
- // register receiver
- mReceiver.registerReceiver();
- }
-
- // Utility method to start a thread to read application labels and icons
- private void initResourceThread() {
- //load resources now
- if(mResourceThread.isAlive()) {
- mResourceThread.interrupt();
- }
- mResourceThread.loadAllResources(mAppInfoAdapter.getAppList());
- }
-
- private void initComputeSizes() {
- // initiate compute pkg sizes
- if (localLOGV) Log.i(TAG, "Initiating compute sizes for first time");
- if (mAppInfoAdapter.getCount() > 0) {
- mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo(0),
- COMPUTE_PKG_SIZE_DONE);
- } else {
- mComputeSizes = true;
- }
- }
-
- private void showEmptyViewIfListEmpty() {
- if (localLOGV) Log.i(TAG, "Checking for empty view");
- if (mAppInfoAdapter.getCount() > 0) {
- mEmptyView.setVisibility(View.GONE);
- } else {
- mEmptyView.setVisibility(View.VISIBLE);
- }
- }
-
- private void createListView() {
- dismissLoadingMsg();
- // get list and set listeners and adapter
- ListView lv= (ListView) findViewById(android.R.id.list);
- lv.setAdapter(mAppInfoAdapter);
- lv.setOnItemClickListener(this);
- lv.setSaveEnabled(true);
- lv.setItemsCanFocus(true);
- lv.setOnItemClickListener(this);
- showEmptyViewIfListEmpty();
- }
-
- // 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) {
- mAppList = appList;
- start();
- }
-
- public void run() {
- Map<String, AppInfo> iconMap = new HashMap<String, AppInfo>();
- if(mAppList == null || mAppList.size() <= 0) {
- Log.w(TAG, "Empty or null application list");
- } else {
- 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);
- }
- }
-
- /* 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;
- }
- }
-
- // 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 AppInfo getFromCache(String packageName) {
- if(mAppPropCache == null) {
- return null;
- }
- return mAppPropCache.get(packageName);
- }
-
- 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;
- }
- }
- return -1;
- }
-
- 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) {
- if (position >= mAppLocalList.size()) {
- 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
- // 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);
- }
- if (mInfo.appSize != null) {
- 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);
- }
- }
- if (mAppLocalList.size() > 0) {
- sortList(mSortOrder);
- } else {
- notifyDataSetChanged();
- }
- showEmptyViewIfListEmpty();
- 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(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);
- }
-
- 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);
- }
- }
-
- /**
- * Receives notifications when applications are added/removed.
- */
- private class PackageIntentReceiver extends BroadcastReceiver {
- void registerReceiver() {
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- ManageApplications.this.registerReceiver(this, filter);
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- String actionStr = intent.getAction();
- Uri data = intent.getData();
- String pkgName = data.getEncodedSchemeSpecificPart();
- 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)) {
- 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);
- }
- }
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Intent lIntent = getIntent();
- String action = lIntent.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);
- // 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);
- mReceiver = new PackageIntentReceiver();
- mEmptyView = (TextView) findViewById(R.id.empty_view);
- mObserver = new PkgSizeObserver();
- }
-
- 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();
- showLoadingMsg();
- // Create a thread to load resources
- mResourceThread = new ResourceLoaderThread();
- sendMessageToHandler(INIT_PKG_INFO);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- // 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(Map<String, AppInfo> pAppPropMap) {
- mAppPropMap= pAppPropMap;
- }
-
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- 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) {
- return 0;
- }
- return -1;
- }
- private Map<String, AppInfo> mAppPropMap;
- }
-
- // utility method used to start sub activity
- private void startApplicationDetailsActivity(ApplicationInfo info, PackageStats ps) {
- // Create intent to start new activity
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(this, InstalledAppDetails.class);
- 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);
- }
-
- @Override
- public boolean onCreateOptionsMenu(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;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (mComputeSizes) {
- 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;
- }
-
- @Override
- public boolean onOptionsItemSelected(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 (mAlertDlgBuilder == null) {
- mAlertDlgBuilder = 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);
- }
- mAlertDlgBuilder.show();
- }
- return true;
- }
-
- public void onItemClick(AdapterView<?> parent, View view, int position,
- long id) {
- 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();
- }
-
- public void onClick(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;
- }
- sendMessageToHandler(REORDER_LIST, newOption);
- }
-}