Fix issues 6512411 and 6512951 in ManageApplications.

6512411 java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
6512951 Settings crash while returning from App info screen

Also fix padding around the UI, and display of storage use.

Change-Id: Ibfcfe1a4a80f25f81ba2cabbb2e3d60aaa9ac04e
This commit is contained in:
Dianne Hackborn
2012-05-17 18:05:17 -07:00
parent a8e3ab89d6
commit a4af18755e

View File

@@ -42,6 +42,7 @@ import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceFrameLayout;
import android.provider.Settings; import android.provider.Settings;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
import android.support.v4.view.PagerTabStrip; import android.support.v4.view.PagerTabStrip;
@@ -55,17 +56,13 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView; import android.widget.AbsListView;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.Filter; import android.widget.Filter;
import android.widget.Filterable; import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.android.internal.app.IMediaContainerService; import com.android.internal.app.IMediaContainerService;
@@ -122,6 +119,11 @@ final class CanBeOnSdCardChecker {
} }
} }
interface AppClickListener {
void onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent,
View view, int position, long id);
}
/** /**
* Activity to pick an application that will be used to display installation information and * 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 * options to uninstall/delete user data for system applications. This activity
@@ -129,7 +131,7 @@ final class CanBeOnSdCardChecker {
* intent. * intent.
*/ */
public class ManageApplications extends Fragment implements public class ManageApplications extends Fragment implements
OnItemClickListener, DialogInterface.OnClickListener, AppClickListener, DialogInterface.OnClickListener,
DialogInterface.OnDismissListener { DialogInterface.OnDismissListener {
static final String TAG = "ManageApplications"; static final String TAG = "ManageApplications";
@@ -174,11 +176,10 @@ public class ManageApplications extends Fragment implements
public static class TabInfo implements OnItemClickListener { public static class TabInfo implements OnItemClickListener {
public final ManageApplications mOwner; public final ManageApplications mOwner;
public final ApplicationsState mApplicationsState; public final ApplicationsState mApplicationsState;
public final IMediaContainerService mContainerService;
public final CharSequence mLabel; public final CharSequence mLabel;
public final int mListType; public final int mListType;
public final int mFilter; public final int mFilter;
public final OnItemClickListener mClickListener; public final AppClickListener mClickListener;
public final CharSequence mInvalidSizeStr; public final CharSequence mInvalidSizeStr;
public final CharSequence mComputingSizeStr; public final CharSequence mComputingSizeStr;
private final Bundle mSavedInstanceState; private final Bundle mSavedInstanceState;
@@ -187,6 +188,8 @@ public class ManageApplications extends Fragment implements
public LayoutInflater mInflater; public LayoutInflater mInflater;
public View mRootView; public View mRootView;
private IMediaContainerService mContainerService;
private View mLoadingContainer; private View mLoadingContainer;
private View mListContainer; private View mListContainer;
@@ -200,6 +203,7 @@ public class ManageApplications extends Fragment implements
private TextView mStorageChartLabel; private TextView mStorageChartLabel;
private TextView mUsedStorageText; private TextView mUsedStorageText;
private TextView mFreeStorageText; private TextView mFreeStorageText;
private long mFreeStorage = 0, mAppStorage = 0, mTotalStorage = 0;
private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage; private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
final Runnable mRunningProcessesAvail = new Runnable() { final Runnable mRunningProcessesAvail = new Runnable() {
@@ -209,12 +213,10 @@ public class ManageApplications extends Fragment implements
}; };
public TabInfo(ManageApplications owner, ApplicationsState apps, public TabInfo(ManageApplications owner, ApplicationsState apps,
IMediaContainerService containerService, CharSequence label, int listType, AppClickListener clickListener,
CharSequence label, int listType, OnItemClickListener clickListener,
Bundle savedInstanceState) { Bundle savedInstanceState) {
mOwner = owner; mOwner = owner;
mApplicationsState = apps; mApplicationsState = apps;
mContainerService = containerService;
mLabel = label; mLabel = label;
mListType = listType; mListType = listType;
switch (listType) { switch (listType) {
@@ -228,6 +230,11 @@ public class ManageApplications extends Fragment implements
mSavedInstanceState = savedInstanceState; mSavedInstanceState = savedInstanceState;
} }
public void setContainerService(IMediaContainerService containerService) {
mContainerService = containerService;
updateStorageUsage();
}
public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) { public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
if (mRootView != null) { if (mRootView != null) {
return mRootView; return mRootView;
@@ -260,6 +267,14 @@ public class ManageApplications extends Fragment implements
mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText); mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText); mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false); Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
if (mFilter == FILTER_APPS_SDCARD) {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.sd_card_storage));
} else {
mStorageChartLabel.setText(mOwner.getActivity().getText(
R.string.internal_storage));
}
applyCurrentStorage();
} }
mRunningProcessesView = (RunningProcessesView)mRootView.findViewById( mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
R.id.running_processes); R.id.running_processes);
@@ -270,6 +285,15 @@ public class ManageApplications extends Fragment implements
return mRootView; return mRootView;
} }
public void detachView() {
if (mRootView != null) {
ViewGroup group = (ViewGroup)mRootView.getParent();
if (group != null) {
group.removeView(mRootView);
}
}
}
public void resume(int sortOrder) { public void resume(int sortOrder) {
if (mApplications != null) { if (mApplications != null) {
mApplications.resume(sortOrder); mApplications.resume(sortOrder);
@@ -295,27 +319,22 @@ public class ManageApplications extends Fragment implements
} }
void updateStorageUsage() { void updateStorageUsage() {
// Fragment view not yet created?
if (mRootView == null) return;
// Make sure a callback didn't come at an inopportune time. // Make sure a callback didn't come at an inopportune time.
if (mOwner.getActivity() == null) return; if (mOwner.getActivity() == null) return;
// Doesn't make sense for stuff that is not an app list. // Doesn't make sense for stuff that is not an app list.
if (mApplications == null) return; if (mApplications == null) return;
long freeStorage = 0; mFreeStorage = 0;
long appStorage = 0; mAppStorage = 0;
long totalStorage = 0; mTotalStorage = 0;
CharSequence newLabel = null;
if (mFilter == FILTER_APPS_SDCARD) { if (mFilter == FILTER_APPS_SDCARD) {
newLabel = mOwner.getActivity().getText(R.string.sd_card_storage);
if (mContainerService != null) { if (mContainerService != null) {
try { try {
final long[] stats = mContainerService.getFileSystemStats( final long[] stats = mContainerService.getFileSystemStats(
Environment.getExternalStorageDirectory().getPath()); Environment.getExternalStorageDirectory().getPath());
totalStorage = stats[0]; mTotalStorage = stats[0];
freeStorage = stats[1]; mFreeStorage = stats[1];
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Problem in container service", e); Log.w(TAG, "Problem in container service", e);
} }
@@ -325,18 +344,16 @@ public class ManageApplications extends Fragment implements
final int N = mApplications.getCount(); final int N = mApplications.getCount();
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i); ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
appStorage += ae.externalCodeSize + ae.externalDataSize; mAppStorage += ae.externalCodeSize + ae.externalDataSize;
} }
} }
} else { } else {
newLabel = mOwner.getActivity().getText(R.string.internal_storage);
if (mContainerService != null) { if (mContainerService != null) {
try { try {
final long[] stats = mContainerService.getFileSystemStats( final long[] stats = mContainerService.getFileSystemStats(
Environment.getDataDirectory().getPath()); Environment.getDataDirectory().getPath());
totalStorage = stats[0]; mTotalStorage = stats[0];
freeStorage = stats[1]; mFreeStorage = stats[1];
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, "Problem in container service", e); Log.w(TAG, "Problem in container service", e);
} }
@@ -347,21 +364,27 @@ public class ManageApplications extends Fragment implements
final int N = mApplications.getCount(); final int N = mApplications.getCount();
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i); ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
appStorage += ae.codeSize + ae.dataSize; mAppStorage += ae.codeSize + ae.dataSize;
if (emulatedStorage) { if (emulatedStorage) {
appStorage += ae.externalCodeSize + ae.externalDataSize; mAppStorage += ae.externalCodeSize + ae.externalDataSize;
} }
} }
} }
freeStorage += mApplicationsState.sumCacheSizes(); mFreeStorage += mApplicationsState.sumCacheSizes();
} }
if (newLabel != null) {
mStorageChartLabel.setText(newLabel); applyCurrentStorage();
} }
if (totalStorage > 0) {
mColorBar.setRatios((totalStorage-freeStorage-appStorage)/(float)totalStorage, void applyCurrentStorage() {
appStorage/(float)totalStorage, freeStorage/(float)totalStorage); // If view hierarchy is not yet created, no views to update.
long usedStorage = totalStorage - freeStorage; if (mRootView == null) {
return;
}
if (mTotalStorage > 0) {
mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage,
mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage);
long usedStorage = mTotalStorage - mFreeStorage;
if (mLastUsedStorage != usedStorage) { if (mLastUsedStorage != usedStorage) {
mLastUsedStorage = usedStorage; mLastUsedStorage = usedStorage;
String sizeStr = Formatter.formatShortFileSize( String sizeStr = Formatter.formatShortFileSize(
@@ -369,10 +392,10 @@ public class ManageApplications extends Fragment implements
mUsedStorageText.setText(mOwner.getActivity().getResources().getString( mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
R.string.service_foreground_processes, sizeStr)); R.string.service_foreground_processes, sizeStr));
} }
if (mLastFreeStorage != freeStorage) { if (mLastFreeStorage != mFreeStorage) {
mLastFreeStorage = freeStorage; mLastFreeStorage = mFreeStorage;
String sizeStr = Formatter.formatShortFileSize( String sizeStr = Formatter.formatShortFileSize(
mOwner.getActivity(), freeStorage); mOwner.getActivity(), mFreeStorage);
mFreeStorageText.setText(mOwner.getActivity().getResources().getString( mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
R.string.service_background_processes, sizeStr)); R.string.service_background_processes, sizeStr));
} }
@@ -391,7 +414,7 @@ public class ManageApplications extends Fragment implements
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mClickListener.onItemClick(parent, view, position, id); mClickListener.onItemClick(this, parent, view, position, id);
} }
void handleRunningProcessesAvail() { void handleRunningProcessesAvail() {
@@ -711,6 +734,7 @@ public class ManageApplications extends Fragment implements
if (mLastSortMode == SORT_ORDER_SIZE) { if (mLastSortMode == SORT_ORDER_SIZE) {
rebuild(false); rebuild(false);
} }
mTab.updateStorageUsage();
} }
public int getCount() { public int getCount() {
@@ -825,24 +849,24 @@ public class ManageApplications extends Fragment implements
mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value); mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
mComputingSizeStr = getActivity().getText(R.string.computing_size); mComputingSizeStr = getActivity().getText(R.string.computing_size);
TabInfo tab = new TabInfo(this, mApplicationsState, mContainerService, TabInfo tab = new TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_third_party), getActivity().getString(R.string.filter_apps_third_party),
LIST_TYPE_DOWNLOADED, this, savedInstanceState); LIST_TYPE_DOWNLOADED, this, savedInstanceState);
mTabs.add(tab); mTabs.add(tab);
if (!Environment.isExternalStorageEmulated()) { if (!Environment.isExternalStorageEmulated()) {
tab = new TabInfo(this, mApplicationsState, mContainerService, tab = new TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_onsdcard), getActivity().getString(R.string.filter_apps_onsdcard),
LIST_TYPE_SDCARD, this, savedInstanceState); LIST_TYPE_SDCARD, this, savedInstanceState);
mTabs.add(tab); mTabs.add(tab);
} }
tab = new TabInfo(this, mApplicationsState, mContainerService, tab = new TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_running), getActivity().getString(R.string.filter_apps_running),
LIST_TYPE_RUNNING, this, savedInstanceState); LIST_TYPE_RUNNING, this, savedInstanceState);
mTabs.add(tab); mTabs.add(tab);
tab = new TabInfo(this, mApplicationsState, mContainerService, tab = new TabInfo(this, mApplicationsState,
getActivity().getString(R.string.filter_apps_all), getActivity().getString(R.string.filter_apps_all),
LIST_TYPE_ALL, this, savedInstanceState); LIST_TYPE_ALL, this, savedInstanceState);
mTabs.add(tab); mTabs.add(tab);
@@ -866,6 +890,12 @@ public class ManageApplications extends Fragment implements
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs); PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light); tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
if (container instanceof PreferenceFrameLayout) {
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
}
if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) { if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
buildResetDialog(); buildResetDialog();
} }
@@ -918,6 +948,17 @@ public class ManageApplications extends Fragment implements
} }
} }
@Override
public void onDestroyView() {
super.onDestroyView();
// We are going to keep the tab data structures around, but they
// are no longer attached to their view hierarchy.
for (int i=0; i<mTabs.size(); i++) {
mTabs.get(i).detachView();
}
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
@@ -1129,10 +1170,10 @@ public class ManageApplications extends Fragment implements
return true; return true;
} }
public void onItemClick(AdapterView<?> parent, View view, int position, public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position,
long id) { long id) {
if (mCurTab != null && mCurTab.mApplications != null) { if (tab.mApplications != null && tab.mApplications.getCount() > position) {
ApplicationsState.AppEntry entry = mCurTab.mApplications.getAppEntry(position); ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position);
mCurrentPkgName = entry.info.packageName; mCurrentPkgName = entry.info.packageName;
startApplicationDetailsActivity(); startApplicationDetailsActivity();
} }
@@ -1170,8 +1211,8 @@ public class ManageApplications extends Fragment implements
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
mContainerService = IMediaContainerService.Stub.asInterface(service); mContainerService = IMediaContainerService.Stub.asInterface(service);
if (mCurTab != null) { for (int i=0; i<mTabs.size(); i++) {
mCurTab.updateStorageUsage(); mTabs.get(i).setContainerService(mContainerService);
} }
} }