summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--[-rwxr-xr-x]res/layout/manage_applications_apps.xml (renamed from res/layout/manage_applications.xml)10
-rw-r--r--res/layout/manage_applications_content.xml41
-rw-r--r--res/layout/manage_applications_running.xml47
-rw-r--r--res/layout/manage_apps_spinner_content.xml51
-rw-r--r--src/com/android/settings/applications/AppViewHolder.java4
-rw-r--r--src/com/android/settings/applications/ApplicationsState.java389
-rw-r--r--src/com/android/settings/applications/InstalledAppDetails.java6
-rw-r--r--src/com/android/settings/applications/ManageApplications.java744
9 files changed, 754 insertions, 540 deletions
diff --git a/Android.mk b/Android.mk
index c08be7f..38732bb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := bouncycastle
-LOCAL_STATIC_JAVA_LIBRARIES := guava
+LOCAL_STATIC_JAVA_LIBRARIES := guava android-support-v4
LOCAL_MODULE_TAGS := optional
diff --git a/res/layout/manage_applications.xml b/res/layout/manage_applications_apps.xml
index da56c99..51ab412 100755..100644
--- a/res/layout/manage_applications.xml
+++ b/res/layout/manage_applications_apps.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- Copyright (C) 2012 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.
@@ -83,12 +83,6 @@
</view>
</LinearLayout>
- <view class="com.android.settings.applications.RunningProcessesView"
- android:id="@+id/running_processes"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone" />
-
<LinearLayout android:id="@+id/loading_container"
android:orientation="vertical"
android:layout_width="match_parent"
@@ -110,4 +104,4 @@
</LinearLayout>
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/res/layout/manage_applications_content.xml b/res/layout/manage_applications_content.xml
new file mode 100644
index 0000000..f72aa03
--- /dev/null
+++ b/res/layout/manage_applications_content.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, 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.
+*/
+-->
+
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+ <android.support.v4.view.PagerTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top">
+ </android.support.v4.view.PagerTabStrip>
+ </android.support.v4.view.ViewPager>
+
+</LinearLayout>
diff --git a/res/layout/manage_applications_running.xml b/res/layout/manage_applications_running.xml
new file mode 100644
index 0000000..634de1c
--- /dev/null
+++ b/res/layout/manage_applications_running.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <view class="com.android.settings.applications.RunningProcessesView"
+ android:id="@+id/running_processes"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
+ <LinearLayout android:id="@+id/loading_container"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="@*android:dimen/preference_fragment_padding_side"
+ android:layout_marginRight="@*android:dimen/preference_fragment_padding_side"
+ android:visibility="gone"
+ android:gravity="center">
+
+ <ProgressBar style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/settings_safetylegal_activity_loading"
+ android:paddingTop="4dip"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/res/layout/manage_apps_spinner_content.xml b/res/layout/manage_apps_spinner_content.xml
deleted file mode 100644
index cbf0a40..0000000
--- a/res/layout/manage_apps_spinner_content.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <Spinner
- android:id="@+id/spinner"
- android:layout_width="wrap_content"
- android:layout_height="48sp"
- android:minWidth="180dp"
- android:layout_marginLeft="@*android:dimen/preference_fragment_padding_side"
- android:layout_marginRight="@*android:dimen/preference_fragment_padding_side"
- />
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@*android:dimen/preference_fragment_padding_side"
- android:layout_marginRight="@*android:dimen/preference_fragment_padding_side"
- android:scaleType="fitXY"
- android:src="?android:attr/listDivider" />
-
- <FrameLayout
- android:id="@+id/spinner_content"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1" />
-
-</LinearLayout>
diff --git a/src/com/android/settings/applications/AppViewHolder.java b/src/com/android/settings/applications/AppViewHolder.java
index 2a12f9b..d23f187 100644
--- a/src/com/android/settings/applications/AppViewHolder.java
+++ b/src/com/android/settings/applications/AppViewHolder.java
@@ -42,7 +42,7 @@ public class AppViewHolder {
}
}
- void updateSizeText(ManageApplications ma, int whichSize) {
+ void updateSizeText(CharSequence invalidSizeStr, int whichSize) {
if (ManageApplications.DEBUG) Log.i(ManageApplications.TAG, "updateSizeText of " + entry.label + " " + entry
+ ": " + entry.sizeStr);
if (entry.sizeStr != null) {
@@ -58,7 +58,7 @@ public class AppViewHolder {
break;
}
} else if (entry.size == ApplicationsState.SIZE_INVALID) {
- appSize.setText(ma.mInvalidSizeStr);
+ appSize.setText(invalidSizeStr);
}
}
} \ No newline at end of file
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index 799b34a..0a5c26e 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -227,24 +227,21 @@ public class ApplicationsState {
PackageIntentReceiver mPackageIntentReceiver;
boolean mResumed;
- Callbacks mCurCallbacks;
- // Information about all applications. Synchronize on mAppEntries
+ // Information about all applications. Synchronize on mEntriesMap
// to protect access to these.
+ final ArrayList<Session> mSessions = new ArrayList<Session>();
+ final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
final HashMap<String, AppEntry> mEntriesMap = new HashMap<String, AppEntry>();
final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>();
long mCurId = 1;
String mCurComputingSizePkg;
+ boolean mSessionsChanged;
- // Rebuilding of app list. Synchronized on mRebuildSync.
- final Object mRebuildSync = new Object();
- boolean mRebuildRequested;
- boolean mRebuildAsync;
- AppFilter mRebuildFilter;
- Comparator<AppEntry> mRebuildComparator;
- ArrayList<AppEntry> mRebuildResult;
+ // Temporary for dispatching session callbacks. Only touched by main thread.
+ final ArrayList<Session> mActiveSessions = new ArrayList<Session>();
/**
* Receives notifications when applications are added/removed.
@@ -262,6 +259,9 @@ public class ApplicationsState {
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(this, sdFilter);
}
+ void unregisterReceiver() {
+ mContext.unregisterReceiver(this);
+ }
@Override
public void onReceive(Context context, Intent intent) {
String actionStr = intent.getAction();
@@ -300,6 +300,21 @@ public class ApplicationsState {
}
}
+ void rebuildActiveSessions() {
+ synchronized (mEntriesMap) {
+ if (!mSessionsChanged) {
+ return;
+ }
+ mActiveSessions.clear();
+ for (int i=0; i<mSessions.size(); i++) {
+ Session s = mSessions.get(i);
+ if (s.mResumed) {
+ mActiveSessions.add(s);
+ }
+ }
+ }
+ }
+
class MainHandler extends Handler {
static final int MSG_REBUILD_COMPLETE = 1;
static final int MSG_PACKAGE_LIST_CHANGED = 2;
@@ -310,35 +325,39 @@ public class ApplicationsState {
@Override
public void handleMessage(Message msg) {
+ rebuildActiveSessions();
switch (msg.what) {
case MSG_REBUILD_COMPLETE: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onRebuildComplete((ArrayList<AppEntry>)msg.obj);
+ Session s = (Session)msg.obj;
+ if (mActiveSessions.contains(s)) {
+ s.mCallbacks.onRebuildComplete(s.mLastAppList);
}
} break;
case MSG_PACKAGE_LIST_CHANGED: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onPackageListChanged();
+ for (int i=0; i<mActiveSessions.size(); i++) {
+ mActiveSessions.get(i).mCallbacks.onPackageListChanged();
}
} break;
case MSG_PACKAGE_ICON_CHANGED: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onPackageIconChanged();
+ for (int i=0; i<mActiveSessions.size(); i++) {
+ mActiveSessions.get(i).mCallbacks.onPackageIconChanged();
}
} break;
case MSG_PACKAGE_SIZE_CHANGED: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onPackageSizeChanged((String)msg.obj);
+ for (int i=0; i<mActiveSessions.size(); i++) {
+ mActiveSessions.get(i).mCallbacks.onPackageSizeChanged(
+ (String)msg.obj);
}
} break;
case MSG_ALL_SIZES_COMPUTED: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onAllSizesComputed();
+ for (int i=0; i<mActiveSessions.size(); i++) {
+ mActiveSessions.get(i).mCallbacks.onAllSizesComputed();
}
} break;
case MSG_RUNNING_STATE_CHANGED: {
- if (mCurCallbacks != null) {
- mCurCallbacks.onRunningStateChanged(msg.arg1 != 0);
+ for (int i=0; i<mActiveSessions.size(); i++) {
+ mActiveSessions.get(i).mCallbacks.onRunningStateChanged(
+ msg.arg1 != 0);
}
} break;
}
@@ -391,157 +410,226 @@ public class ApplicationsState {
}
}
- void resume(Callbacks callbacks) {
- if (DEBUG_LOCKING) Log.v(TAG, "resume about to acquire lock...");
- synchronized (mEntriesMap) {
- mCurCallbacks = callbacks;
- mResumed = true;
- if (mPackageIntentReceiver == null) {
- mPackageIntentReceiver = new PackageIntentReceiver();
- mPackageIntentReceiver.registerReceiver();
- }
- mApplications = mPm.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_DISABLED_COMPONENTS);
- if (mApplications == null) {
- mApplications = new ArrayList<ApplicationInfo>();
- }
-
- if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
- // If an interesting part of the configuration has changed, we
- // should completely reload the app entries.
- mEntriesMap.clear();
- mAppEntries.clear();
- } else {
- for (int i=0; i<mAppEntries.size(); i++) {
- mAppEntries.get(i).sizeStale = true;
- }
- }
+ public class Session {
+ final Callbacks mCallbacks;
+ boolean mResumed;
- for (int i=0; i<mApplications.size(); i++) {
- final ApplicationInfo info = mApplications.get(i);
- // Need to trim out any applications that are disabled by
- // something different than the user.
- if (!info.enabled && info.enabledSetting
- != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
- mApplications.remove(i);
- i--;
- continue;
- }
- final AppEntry entry = mEntriesMap.get(info.packageName);
- if (entry != null) {
- entry.info = info;
+ // Rebuilding of app list. Synchronized on mRebuildSync.
+ final Object mRebuildSync = new Object();
+ boolean mRebuildRequested;
+ boolean mRebuildAsync;
+ AppFilter mRebuildFilter;
+ Comparator<AppEntry> mRebuildComparator;
+ ArrayList<AppEntry> mRebuildResult;
+ ArrayList<AppEntry> mLastAppList;
+
+ Session(Callbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ public void resume() {
+ if (DEBUG_LOCKING) Log.v(TAG, "resume about to acquire lock...");
+ synchronized (mEntriesMap) {
+ if (!mResumed) {
+ mResumed = true;
+ mSessionsChanged = true;
+ doResumeIfNeededLocked();
}
}
- mCurComputingSizePkg = null;
- if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) {
- mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES);
- }
if (DEBUG_LOCKING) Log.v(TAG, "...resume releasing lock");
}
- }
- void pause() {
- if (DEBUG_LOCKING) Log.v(TAG, "pause about to acquire lock...");
- synchronized (mEntriesMap) {
- mCurCallbacks = null;
- mResumed = false;
- if (DEBUG_LOCKING) Log.v(TAG, "...pause releasing lock");
+ public void pause() {
+ if (DEBUG_LOCKING) Log.v(TAG, "pause about to acquire lock...");
+ synchronized (mEntriesMap) {
+ if (mResumed) {
+ mResumed = false;
+ mSessionsChanged = true;
+ mBackgroundHandler.removeMessages(BackgroundHandler.MSG_REBUILD_LIST, this);
+ doPauseIfNeededLocked();
+ }
+ if (DEBUG_LOCKING) Log.v(TAG, "...pause releasing lock");
+ }
}
- }
- // Creates a new list of app entries with the given filter and comparator.
- ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator) {
- synchronized (mRebuildSync) {
- mRebuildRequested = true;
- mRebuildAsync = false;
- mRebuildFilter = filter;
- mRebuildComparator = comparator;
- mRebuildResult = null;
- if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_REBUILD_LIST)) {
- mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_REBUILD_LIST);
- }
-
- // We will wait for .25s for the list to be built.
- long waitend = SystemClock.uptimeMillis()+250;
-
- while (mRebuildResult == null) {
- long now = SystemClock.uptimeMillis();
- if (now >= waitend) {
- break;
+ // Creates a new list of app entries with the given filter and comparator.
+ ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator) {
+ synchronized (mRebuildSync) {
+ synchronized (mEntriesMap) {
+ mRebuildingSessions.add(this);
+ mRebuildRequested = true;
+ mRebuildAsync = false;
+ mRebuildFilter = filter;
+ mRebuildComparator = comparator;
+ mRebuildResult = null;
+ if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_REBUILD_LIST)) {
+ Message msg = mBackgroundHandler.obtainMessage(
+ BackgroundHandler.MSG_REBUILD_LIST);
+ mBackgroundHandler.sendMessage(msg);
+ }
}
- try {
- mRebuildSync.wait(waitend - now);
- } catch (InterruptedException e) {
+
+ // We will wait for .25s for the list to be built.
+ long waitend = SystemClock.uptimeMillis()+250;
+
+ while (mRebuildResult == null) {
+ long now = SystemClock.uptimeMillis();
+ if (now >= waitend) {
+ break;
+ }
+ try {
+ mRebuildSync.wait(waitend - now);
+ } catch (InterruptedException e) {
+ }
}
- }
- mRebuildAsync = true;
+ mRebuildAsync = true;
- return mRebuildResult;
+ return mRebuildResult;
+ }
}
- }
- void handleRebuildList() {
- AppFilter filter;
- Comparator<AppEntry> comparator;
- synchronized (mRebuildSync) {
- if (!mRebuildRequested) {
- return;
+ void handleRebuildList() {
+ AppFilter filter;
+ Comparator<AppEntry> comparator;
+ synchronized (mRebuildSync) {
+ if (!mRebuildRequested) {
+ return;
+ }
+
+ filter = mRebuildFilter;
+ comparator = mRebuildComparator;
+ mRebuildRequested = false;
+ mRebuildFilter = null;
+ mRebuildComparator = null;
}
- filter = mRebuildFilter;
- comparator = mRebuildComparator;
- mRebuildRequested = false;
- mRebuildFilter = null;
- mRebuildComparator = null;
- }
+ Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
- Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+ if (filter != null) {
+ filter.init();
+ }
+
+ List<ApplicationInfo> apps;
+ synchronized (mEntriesMap) {
+ apps = new ArrayList<ApplicationInfo>(mApplications);
+ }
- if (filter != null) {
- filter.init();
+ ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
+ if (DEBUG) Log.i(TAG, "Rebuilding...");
+ for (int i=0; i<apps.size(); i++) {
+ ApplicationInfo info = apps.get(i);
+ if (filter == null || filter.filterApp(info)) {
+ synchronized (mEntriesMap) {
+ if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock");
+ AppEntry entry = getEntryLocked(info);
+ entry.ensureLabel(mContext);
+ if (DEBUG) Log.i(TAG, "Using " + info.packageName + ": " + entry);
+ filteredApps.add(entry);
+ if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock");
+ }
+ }
+ }
+
+ Collections.sort(filteredApps, comparator);
+
+ synchronized (mRebuildSync) {
+ if (!mRebuildRequested) {
+ mLastAppList = filteredApps;
+ if (!mRebuildAsync) {
+ mRebuildResult = filteredApps;
+ mRebuildSync.notifyAll();
+ } else {
+ if (!mMainHandler.hasMessages(MainHandler.MSG_REBUILD_COMPLETE, this)) {
+ Message msg = mMainHandler.obtainMessage(
+ MainHandler.MSG_REBUILD_COMPLETE, this);
+ mMainHandler.sendMessage(msg);
+ }
+ }
+ }
+ }
+
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
-
- List<ApplicationInfo> apps;
+
+ public void release() {
+ pause();
+ synchronized (mEntriesMap) {
+ mSessions.remove(this);
+ }
+ }
+ }
+
+ public Session newSession(Callbacks callbacks) {
+ Session s = new Session(callbacks);
synchronized (mEntriesMap) {
- apps = new ArrayList<ApplicationInfo>(mApplications);
+ mSessions.add(s);
}
+ return s;
+ }
- ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
- if (DEBUG) Log.i(TAG, "Rebuilding...");
- for (int i=0; i<apps.size(); i++) {
- ApplicationInfo info = apps.get(i);
- if (filter == null || filter.filterApp(info)) {
- synchronized (mEntriesMap) {
- if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock");
- AppEntry entry = getEntryLocked(info);
- entry.ensureLabel(mContext);
- if (DEBUG) Log.i(TAG, "Using " + info.packageName + ": " + entry);
- filteredApps.add(entry);
- if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock");
- }
+ void doResumeIfNeededLocked() {
+ if (mResumed) {
+ return;
+ }
+ mResumed = true;
+ if (mPackageIntentReceiver == null) {
+ mPackageIntentReceiver = new PackageIntentReceiver();
+ mPackageIntentReceiver.registerReceiver();
+ }
+ mApplications = mPm.getInstalledApplications(
+ PackageManager.GET_UNINSTALLED_PACKAGES |
+ PackageManager.GET_DISABLED_COMPONENTS);
+ if (mApplications == null) {
+ mApplications = new ArrayList<ApplicationInfo>();
+ }
+
+ if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
+ // If an interesting part of the configuration has changed, we
+ // should completely reload the app entries.
+ mEntriesMap.clear();
+ mAppEntries.clear();
+ } else {
+ for (int i=0; i<mAppEntries.size(); i++) {
+ mAppEntries.get(i).sizeStale = true;
}
}
- Collections.sort(filteredApps, comparator);
-
- synchronized (mRebuildSync) {
- if (!mRebuildRequested) {
- if (!mRebuildAsync) {
- mRebuildResult = filteredApps;
- mRebuildSync.notifyAll();
- } else {
- if (!mMainHandler.hasMessages(MainHandler.MSG_REBUILD_COMPLETE)) {
- Message msg = mMainHandler.obtainMessage(
- MainHandler.MSG_REBUILD_COMPLETE, filteredApps);
- mMainHandler.sendMessage(msg);
- }
- }
+ for (int i=0; i<mApplications.size(); i++) {
+ final ApplicationInfo info = mApplications.get(i);
+ // Need to trim out any applications that are disabled by
+ // something different than the user.
+ if (!info.enabled && info.enabledSetting
+ != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+ mApplications.remove(i);
+ i--;
+ continue;
+ }
+ final AppEntry entry = mEntriesMap.get(info.packageName);
+ if (entry != null) {
+ entry.info = info;
}
}
+ mCurComputingSizePkg = null;
+ if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) {
+ mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES);
+ }
+ }
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ void doPauseIfNeededLocked() {
+ if (!mResumed) {
+ return;
+ }
+ for (int i=0; i<mSessions.size(); i++) {
+ if (mSessions.get(i).mResumed) {
+ return;
+ }
+ }
+ mResumed = false;
+ if (mPackageIntentReceiver != null) {
+ mPackageIntentReceiver.unregisterReceiver();
+ mPackageIntentReceiver = null;
+ }
}
AppEntry getEntry(String packageName) {
@@ -772,7 +860,18 @@ public class ApplicationsState {
@Override
public void handleMessage(Message msg) {
// Always try rebuilding list first thing, if needed.
- handleRebuildList();
+ ArrayList<Session> rebuildingSessions = null;
+ synchronized (mEntriesMap) {
+ if (mRebuildingSessions.size() > 0) {
+ rebuildingSessions = new ArrayList<Session>(mRebuildingSessions);
+ mRebuildingSessions.clear();
+ }
+ }
+ if (rebuildingSessions != null) {
+ for (int i=0; i<rebuildingSessions.size(); i++) {
+ rebuildingSessions.get(i).handleRebuildList();
+ }
+ }
switch (msg.what) {
case MSG_REBUILD_LIST: {
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 6fa20ce..bd77118 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -98,6 +98,7 @@ public class InstalledAppDetails extends Fragment
private AppWidgetManager mAppWidgetManager;
private DevicePolicyManager mDpm;
private ApplicationsState mState;
+ private ApplicationsState.Session mSession;
private ApplicationsState.AppEntry mAppEntry;
private PackageInfo mPackageInfo;
private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
@@ -348,6 +349,7 @@ public class InstalledAppDetails extends Fragment
super.onCreate(icicle);
mState = ApplicationsState.getInstance(getActivity().getApplication());
+ mSession = mState.newSession(this);
mPm = getActivity().getPackageManager();
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
mUsbManager = IUsbManager.Stub.asInterface(b);
@@ -423,7 +425,7 @@ public class InstalledAppDetails extends Fragment
public void onResume() {
super.onResume();
- mState.resume(this);
+ mSession.resume();
if (!refreshUi()) {
setIntentAndFinish(true, true);
}
@@ -432,7 +434,7 @@ public class InstalledAppDetails extends Fragment
@Override
public void onPause() {
super.onPause();
- mState.pause();
+ mSession.pause();
}
@Override
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 37967d1..1448dfd 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -18,11 +18,9 @@ package com.android.settings.applications;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static com.android.settings.Utils.prepareCustomPreferencesList;
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.DialogFragment;
import android.app.Fragment;
import android.app.INotificationManager;
import android.content.ComponentName;
@@ -45,9 +43,11 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.preference.PreferenceActivity;
import android.provider.Settings;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.PagerTabStrip;
+import android.support.v4.view.ViewPager;
import android.text.format.Formatter;
import android.util.Log;
-import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -75,6 +75,7 @@ import com.android.settings.Settings.RunningServicesActivity;
import com.android.settings.Settings.StorageUseActivity;
import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.deviceinfo.StorageMeasurement;
+import com.android.settings.Utils;
import java.util.ArrayList;
import java.util.Comparator;
@@ -169,8 +170,242 @@ public class ManageApplications extends Fragment implements
private int mFilterApps = FILTER_APPS_THIRD_PARTY;
private ApplicationsState mApplicationsState;
- private ApplicationsAdapter mApplicationsAdapter;
-
+
+ public static class TabInfo implements OnItemClickListener {
+ public final ManageApplications mOwner;
+ public final ApplicationsState mApplicationsState;
+ public final IMediaContainerService mContainerService;
+ public final CharSequence mLabel;
+ public final int mListType;
+ public final int mFilter;
+ public final OnItemClickListener mClickListener;
+ public final CharSequence mInvalidSizeStr;
+ public final CharSequence mComputingSizeStr;
+ private final Bundle mSavedInstanceState;
+
+ public ApplicationsAdapter mApplications;
+ public LayoutInflater mInflater;
+ public View mRootView;
+
+ private View mLoadingContainer;
+
+ private View mListContainer;
+
+ // ListView used to display list
+ private ListView mListView;
+ // Custom view used to display running processes
+ private RunningProcessesView mRunningProcessesView;
+
+ private LinearColorBar mColorBar;
+ private TextView mStorageChartLabel;
+ private TextView mUsedStorageText;
+ private TextView mFreeStorageText;
+ private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
+
+ final Runnable mRunningProcessesAvail = new Runnable() {
+ public void run() {
+ handleRunningProcessesAvail();
+ }
+ };
+
+ public TabInfo(ManageApplications owner, ApplicationsState apps,
+ IMediaContainerService containerService,
+ CharSequence label, int listType, OnItemClickListener clickListener,
+ Bundle savedInstanceState) {
+ mOwner = owner;
+ mApplicationsState = apps;
+ mContainerService = containerService;
+ mLabel = label;
+ mListType = listType;
+ switch (listType) {
+ case LIST_TYPE_DOWNLOADED: mFilter = FILTER_APPS_THIRD_PARTY; break;
+ case LIST_TYPE_SDCARD: mFilter = FILTER_APPS_SDCARD; break;
+ default: mFilter = FILTER_APPS_ALL; break;
+ }
+ mClickListener = clickListener;
+ mInvalidSizeStr = owner.getActivity().getText(R.string.invalid_size_value);
+ mComputingSizeStr = owner.getActivity().getText(R.string.computing_size);
+ mSavedInstanceState = savedInstanceState;
+ }
+
+ public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
+ if (mRootView != null) {
+ return mRootView;
+ }
+
+ mInflater = inflater;
+ mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING
+ ? R.layout.manage_applications_running
+ : R.layout.manage_applications_apps, null);
+ mLoadingContainer = mRootView.findViewById(R.id.loading_container);
+ mLoadingContainer.setVisibility(View.VISIBLE);
+ mListContainer = mRootView.findViewById(R.id.list_container);
+ if (mListContainer != null) {
+ // Create adapter and list view here
+ View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
+ ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
+ if (emptyView != null) {
+ lv.setEmptyView(emptyView);
+ }
+ lv.setOnItemClickListener(this);
+ lv.setSaveEnabled(true);
+ lv.setItemsCanFocus(true);
+ lv.setTextFilterEnabled(true);
+ mListView = lv;
+ mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
+ mListView.setAdapter(mApplications);
+ mListView.setRecyclerListener(mApplications);
+ mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
+ mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
+ mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
+ mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
+ Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
+ }
+ mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
+ R.id.running_processes);
+ if (mRunningProcessesView != null) {
+ mRunningProcessesView.doCreate(mSavedInstanceState);
+ }
+
+ return mRootView;
+ }
+
+ public void resume(int sortOrder) {
+ if (mApplications != null) {
+ mApplications.resume(sortOrder);
+ }
+ if (mRunningProcessesView != null) {
+ boolean haveData = mRunningProcessesView.doResume(mOwner, mRunningProcessesAvail);
+ if (haveData) {
+ mRunningProcessesView.setVisibility(View.VISIBLE);
+ mLoadingContainer.setVisibility(View.INVISIBLE);
+ } else {
+ mLoadingContainer.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ public void pause() {
+ if (mApplications != null) {
+ mApplications.pause();
+ }
+ if (mRunningProcessesView != null) {
+ mRunningProcessesView.doPause();
+ }
+ }
+
+ void updateStorageUsage() {
+ // Fragment view not yet created?
+ if (mRootView == null) return;
+ // Make sure a callback didn't come at an inopportune time.
+ if (mOwner.getActivity() == null) return;
+ // Doesn't make sense for stuff that is not an app list.
+ if (mApplications == null) return;
+
+ long freeStorage = 0;
+ long appStorage = 0;
+ long totalStorage = 0;
+ CharSequence newLabel = null;
+
+ if (mFilter == FILTER_APPS_SDCARD) {
+ newLabel = mOwner.getActivity().getText(R.string.sd_card_storage);
+
+ if (mContainerService != null) {
+ try {
+ final long[] stats = mContainerService.getFileSystemStats(
+ Environment.getExternalStorageDirectory().getPath());
+ totalStorage = stats[0];
+ freeStorage = stats[1];
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem in container service", e);
+ }
+ }
+
+ if (mApplications != null) {
+ final int N = mApplications.getCount();
+ for (int i=0; i<N; i++) {
+ ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
+ appStorage += ae.externalCodeSize + ae.externalDataSize;
+ }
+ }
+ } else {
+ newLabel = mOwner.getActivity().getText(R.string.internal_storage);
+
+ if (mContainerService != null) {
+ try {
+ final long[] stats = mContainerService.getFileSystemStats(
+ Environment.getDataDirectory().getPath());
+ totalStorage = stats[0];
+ freeStorage = stats[1];
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem in container service", e);
+ }
+ }
+
+ final boolean emulatedStorage = Environment.isExternalStorageEmulated();
+ if (mApplications != null) {
+ final int N = mApplications.getCount();
+ for (int i=0; i<N; i++) {
+ ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
+ appStorage += ae.codeSize + ae.dataSize;
+ if (emulatedStorage) {
+ appStorage += ae.externalCodeSize + ae.externalDataSize;
+ }
+ }
+ }
+ freeStorage += mApplicationsState.sumCacheSizes();
+ }
+ if (newLabel != null) {
+ mStorageChartLabel.setText(newLabel);
+ }
+ if (totalStorage > 0) {
+ mColorBar.setRatios((totalStorage-freeStorage-appStorage)/(float)totalStorage,
+ appStorage/(float)totalStorage, freeStorage/(float)totalStorage);
+ long usedStorage = totalStorage - freeStorage;
+ if (mLastUsedStorage != usedStorage) {
+ mLastUsedStorage = usedStorage;
+ String sizeStr = Formatter.formatShortFileSize(
+ mOwner.getActivity(), usedStorage);
+ mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
+ R.string.service_foreground_processes, sizeStr));
+ }
+ if (mLastFreeStorage != freeStorage) {
+ mLastFreeStorage = freeStorage;
+ String sizeStr = Formatter.formatShortFileSize(
+ mOwner.getActivity(), freeStorage);
+ mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
+ R.string.service_background_processes, sizeStr));
+ }
+ } else {
+ mColorBar.setRatios(0, 0, 0);
+ if (mLastUsedStorage != -1) {
+ mLastUsedStorage = -1;
+ mUsedStorageText.setText("");
+ }
+ if (mLastFreeStorage != -1) {
+ mLastFreeStorage = -1;
+ mFreeStorageText.setText("");
+ }
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ mClickListener.onItemClick(parent, view, position, id);
+ }
+
+ void handleRunningProcessesAvail() {
+ mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
+ mOwner.getActivity(), android.R.anim.fade_out));
+ mRunningProcessesView.startAnimation(AnimationUtils.loadAnimation(
+ mOwner.getActivity(), android.R.anim.fade_in));
+ mRunningProcessesView.setVisibility(View.VISIBLE);
+ mLoadingContainer.setVisibility(View.GONE);
+ }
+ }
+ private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+ TabInfo mCurTab = null;
+
// Size resource used for packages whose size computation failed for some reason
CharSequence mInvalidSizeStr;
private CharSequence mComputingSizeStr;
@@ -180,59 +415,72 @@ public class ManageApplications extends Fragment implements
private String mCurrentPkgName;
- private View mLoadingContainer;
-
- private View mListContainer;
-
- // ListView used to display list
- private ListView mListView;
- // Custom view used to display running processes
- private RunningProcessesView mRunningProcessesView;
-
- LinearColorBar mColorBar;
- TextView mStorageChartLabel;
- TextView mUsedStorageText;
- TextView mFreeStorageText;
-
private Menu mOptionsMenu;
// These are for keeping track of activity and spinner switch state.
- private int mCurView;
- private boolean mCreatedRunning;
-
- private boolean mResumedRunning;
private boolean mActivityResumed;
- private boolean mLastShowedInternalStorage = true;
- private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
-
static final int LIST_TYPE_DOWNLOADED = 0;
static final int LIST_TYPE_RUNNING = 1;
static final int LIST_TYPE_SDCARD = 2;
static final int LIST_TYPE_ALL = 3;
- private View mRootView;
private boolean mShowBackground = false;
private int mDefaultListType = -1;
- private SparseIntArray mIndexToType = new SparseIntArray(4);
- private Spinner mSpinner;
- private FrameLayout mSpinnerContent;
+ private ViewGroup mContentContainer;
+ private View mRootView;
+ private ViewPager mViewPager;
AlertDialog mResetDialog;
- final Runnable mRunningProcessesAvail = new Runnable() {
- public void run() {
- handleRunningProcessesAvail();
+ class MyPagerAdapter extends PagerAdapter
+ implements ViewPager.OnPageChangeListener {
+ int mCurPos = 0;
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ TabInfo tab = mTabs.get(position);
+ View root = tab.build(mInflater, mContentContainer, mRootView);
+ container.addView(root);
+ return root;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ container.removeView((View)object);
}
- };
- static class AppFilterAdapter extends ArrayAdapter<String> {
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
- public AppFilterAdapter(Context context) {
- super(context, R.layout.apps_spinner_item);
- setDropDownViewResource(R.layout.apps_spinner_dropdown_item);
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mTabs.get(position).mLabel;
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ mCurPos = position;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_IDLE) {
+ updateCurrentTab(mCurPos);
+ }
}
}
@@ -245,14 +493,18 @@ public class ManageApplications extends Fragment implements
* 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 ApplicationsAdapter extends BaseAdapter implements Filterable,
+ static class ApplicationsAdapter extends BaseAdapter implements Filterable,
ApplicationsState.Callbacks, AbsListView.RecyclerListener {
private final ApplicationsState mState;
+ private final ApplicationsState.Session mSession;
+ private final TabInfo mTab;
+ private final Context mContext;
private final ArrayList<View> mActive = new ArrayList<View>();
+ private final int mFilterMode;
private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
private ArrayList<ApplicationsState.AppEntry> mEntries;
private boolean mResumed;
- private int mLastFilterMode=-1, mLastSortMode=-1;
+ private int mLastSortMode=-1;
private boolean mWaitingForData;
private int mWhichSize = SIZE_TOTAL;
CharSequence mCurFilterPrefix;
@@ -273,39 +525,41 @@ public class ManageApplications extends Fragment implements
mCurFilterPrefix = constraint;
mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values;
notifyDataSetChanged();
- updateStorageUsage();
+ mTab.updateStorageUsage();
}
};
- public ApplicationsAdapter(ApplicationsState state) {
+ public ApplicationsAdapter(ApplicationsState state, TabInfo tab, int filterMode) {
mState = state;
+ mSession = state.newSession(this);
+ mTab = tab;
+ mContext = tab.mOwner.getActivity();
+ mFilterMode = filterMode;
}
- public void resume(int filter, int sort) {
+ public void resume(int sort) {
if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed);
if (!mResumed) {
mResumed = true;
- mState.resume(this);
- mLastFilterMode = filter;
+ mSession.resume();
mLastSortMode = sort;
rebuild(true);
} else {
- rebuild(filter, sort);
+ rebuild(sort);
}
}
public void pause() {
if (mResumed) {
mResumed = false;
- mState.pause();
+ mSession.pause();
}
}
- public void rebuild(int filter, int sort) {
- if (filter == mLastFilterMode && sort == mLastSortMode) {
+ public void rebuild(int sort) {
+ if (sort == mLastSortMode) {
return;
}
- mLastFilterMode = filter;
mLastSortMode = sort;
rebuild(true);
}
@@ -320,7 +574,7 @@ public class ManageApplications extends Fragment implements
} else {
mWhichSize = SIZE_INTERNAL;
}
- switch (mLastFilterMode) {
+ switch (mFilterMode) {
case FILTER_APPS_THIRD_PARTY:
filterObj = ApplicationsState.THIRD_PARTY_FILTER;
break;
@@ -353,7 +607,7 @@ public class ManageApplications extends Fragment implements
break;
}
ArrayList<ApplicationsState.AppEntry> entries
- = mState.rebuild(filterObj, comparatorObj);
+ = mSession.rebuild(filterObj, comparatorObj);
if (entries == null && !eraseold) {
// Don't have new list yet, but can continue using the old one.
return;
@@ -365,15 +619,15 @@ public class ManageApplications extends Fragment implements
mEntries = null;
}
notifyDataSetChanged();
- updateStorageUsage();
+ mTab.updateStorageUsage();
if (entries == null) {
mWaitingForData = true;
- mListContainer.setVisibility(View.INVISIBLE);
- mLoadingContainer.setVisibility(View.VISIBLE);
+ mTab.mListContainer.setVisibility(View.INVISIBLE);
+ mTab.mLoadingContainer.setVisibility(View.VISIBLE);
} else {
- mListContainer.setVisibility(View.VISIBLE);
- mLoadingContainer.setVisibility(View.GONE);
+ mTab.mListContainer.setVisibility(View.VISIBLE);
+ mTab.mLoadingContainer.setVisibility(View.GONE);
}
}
@@ -399,24 +653,24 @@ public class ManageApplications extends Fragment implements
@Override
public void onRunningStateChanged(boolean running) {
- getActivity().setProgressBarIndeterminateVisibility(running);
+ mTab.mOwner.getActivity().setProgressBarIndeterminateVisibility(running);
}
@Override
public void onRebuildComplete(ArrayList<AppEntry> apps) {
- if (mLoadingContainer.getVisibility() == View.VISIBLE) {
- mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
- getActivity(), android.R.anim.fade_out));
- mListContainer.startAnimation(AnimationUtils.loadAnimation(
- getActivity(), android.R.anim.fade_in));
+ if (mTab.mLoadingContainer.getVisibility() == View.VISIBLE) {
+ mTab.mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
+ mContext, android.R.anim.fade_out));
+ mTab.mListContainer.startAnimation(AnimationUtils.loadAnimation(
+ mContext, android.R.anim.fade_in));
}
- mListContainer.setVisibility(View.VISIBLE);
- mLoadingContainer.setVisibility(View.GONE);
+ mTab.mListContainer.setVisibility(View.VISIBLE);
+ mTab.mLoadingContainer.setVisibility(View.GONE);
mWaitingForData = false;
mBaseEntries = apps;
mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
notifyDataSetChanged();
- updateStorageUsage();
+ mTab.updateStorageUsage();
}
@Override
@@ -436,9 +690,9 @@ public class ManageApplications extends Fragment implements
AppViewHolder holder = (AppViewHolder)mActive.get(i).getTag();
if (holder.entry.info.packageName.equals(packageName)) {
synchronized (holder.entry) {
- holder.updateSizeText(ManageApplications.this, mWhichSize);
+ holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
}
- if (holder.entry.info.packageName.equals(mCurrentPkgName)
+ if (holder.entry.info.packageName.equals(mTab.mOwner.mCurrentPkgName)
&& mLastSortMode == SORT_ORDER_SIZE) {
// We got the size information for the last app the
// user viewed, and are sorting by size... they may
@@ -446,7 +700,7 @@ public class ManageApplications extends Fragment implements
// the list with the new size to reflect it to the user.
rebuild(false);
}
- updateStorageUsage();
+ mTab.updateStorageUsage();
return;
}
}
@@ -478,7 +732,7 @@ public class ManageApplications extends Fragment implements
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
- AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
+ AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView);
convertView = holder.rootView;
// Bind the data efficiently with the holder
@@ -487,7 +741,7 @@ public class ManageApplications extends Fragment implements
holder.entry = entry;
if (entry.label != null) {
holder.appName.setText(entry.label);
- holder.appName.setTextColor(getActivity().getResources().getColorStateList(
+ holder.appName.setTextColor(mContext.getResources().getColorStateList(
entry.info.enabled ? android.R.color.primary_text_dark
: android.R.color.secondary_text_dark));
}
@@ -495,13 +749,13 @@ public class ManageApplications extends Fragment implements
if (entry.icon != null) {
holder.appIcon.setImageDrawable(entry.icon);
}
- holder.updateSizeText(ManageApplications.this, mWhichSize);
+ holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
if (InstalledAppDetails.SUPPORT_DISABLE_APPS) {
holder.disabled.setVisibility(entry.info.enabled ? View.GONE : View.VISIBLE);
} else {
holder.disabled.setVisibility(View.GONE);
}
- if (mLastFilterMode == FILTER_APPS_SDCARD) {
+ if (mFilterMode == FILTER_APPS_SDCARD) {
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setChecked((entry.info.flags
& ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
@@ -532,7 +786,6 @@ public class ManageApplications extends Fragment implements
setHasOptionsMenu(true);
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
- mApplicationsAdapter = new ApplicationsAdapter(mApplicationsState);
Intent intent = getActivity().getIntent();
String action = intent.getAction();
int defaultListType = LIST_TYPE_DOWNLOADED;
@@ -571,82 +824,53 @@ public class ManageApplications extends Fragment implements
mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
mComputingSizeStr = getActivity().getText(R.string.computing_size);
- }
+ TabInfo tab = new TabInfo(this, mApplicationsState, mContainerService,
+ getActivity().getString(R.string.filter_apps_third_party),
+ LIST_TYPE_DOWNLOADED, this, savedInstanceState);
+ mTabs.add(tab);
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- // initialize the inflater
- mInflater = inflater;
- mRootView = inflater.inflate(R.layout.manage_applications, null);
- mLoadingContainer = mRootView.findViewById(R.id.loading_container);
- mListContainer = mRootView.findViewById(R.id.list_container);
- // Create adapter and list view here
- ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
- View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
- if (emptyView != null) {
- lv.setEmptyView(emptyView);
+ if (!Environment.isExternalStorageEmulated()) {
+ tab = new TabInfo(this, mApplicationsState, mContainerService,
+ getActivity().getString(R.string.filter_apps_onsdcard),
+ LIST_TYPE_SDCARD, this, savedInstanceState);
+ mTabs.add(tab);
}
- lv.setOnItemClickListener(this);
- lv.setSaveEnabled(true);
- lv.setItemsCanFocus(true);
- lv.setOnItemClickListener(this);
- lv.setTextFilterEnabled(true);
- mListView = lv;
- lv.setRecyclerListener(mApplicationsAdapter);
- mListView.setAdapter(mApplicationsAdapter);
- mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
- mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
- mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
- mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
- mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
- R.id.running_processes);
-
- mCreatedRunning = mResumedRunning = false;
- mCurView = VIEW_NOTHING;
-
- View spinnerHost = mInflater.inflate(R.layout.manage_apps_spinner_content,
- container, false);
- mSpinner = (Spinner) spinnerHost.findViewById(R.id.spinner);
- mSpinnerContent = (FrameLayout) spinnerHost.findViewById(R.id.spinner_content);
- mSpinnerContent.addView(mRootView);
+ tab = new TabInfo(this, mApplicationsState, mContainerService,
+ getActivity().getString(R.string.filter_apps_running),
+ LIST_TYPE_RUNNING, this, savedInstanceState);
+ mTabs.add(tab);
- AppFilterAdapter sa = new AppFilterAdapter(getActivity());
- mIndexToType.append(sa.getCount(), LIST_TYPE_DOWNLOADED);
- sa.add(getActivity().getString(R.string.filter_apps_third_party));
- if (!Environment.isExternalStorageEmulated()) {
- mIndexToType.append(sa.getCount(), LIST_TYPE_SDCARD);
- sa.add(getActivity().getString(R.string.filter_apps_onsdcard));
- }
- mIndexToType.append(sa.getCount(), LIST_TYPE_RUNNING);
- sa.add(getActivity().getString(R.string.filter_apps_running));
- mIndexToType.append(sa.getCount(), LIST_TYPE_ALL);
- sa.add(getActivity().getString(R.string.filter_apps_all));
+ tab = new TabInfo(this, mApplicationsState, mContainerService,
+ getActivity().getString(R.string.filter_apps_all),
+ LIST_TYPE_ALL, this, savedInstanceState);
+ mTabs.add(tab);
+ }
- mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent,
- View view, int position, long id) {
- showCurrentList();
- }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Nothing
- }
- });
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // initialize the inflater
+ mInflater = inflater;
- mSpinner.setSelection(getIndex(mDefaultListType));
- mSpinner.setAdapter(sa);
+ View rootView = mInflater.inflate(R.layout.manage_applications_content,
+ container, false);
+ mContentContainer = container;
+ mRootView = rootView;
- prepareCustomPreferencesList(container, spinnerHost, mListView, false);
+ mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
+ MyPagerAdapter adapter = new MyPagerAdapter();
+ mViewPager.setAdapter(adapter);
+ mViewPager.setOnPageChangeListener(adapter);
+ PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
+ tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
buildResetDialog();
}
- return spinnerHost;
+ return rootView;
}
@Override
@@ -658,10 +882,8 @@ public class ManageApplications extends Fragment implements
public void onResume() {
super.onResume();
mActivityResumed = true;
- showCurrentList();
+ updateCurrentTab(mViewPager.getCurrentItem());
updateOptionsMenu();
- mSpinner.setEnabled(true);
- mSpinnerContent.setEnabled(true);
}
@Override
@@ -682,13 +904,9 @@ public class ManageApplications extends Fragment implements
public void onPause() {
super.onPause();
mActivityResumed = false;
- mApplicationsAdapter.pause();
- if (mResumedRunning) {
- mRunningProcessesView.doPause();
- mResumedRunning = false;
+ for (int i=0; i<mTabs.size(); i++) {
+ mTabs.get(i).pause();
}
- mSpinner.setEnabled(false);
- mSpinnerContent.setEnabled(false);
}
@Override
@@ -707,11 +925,14 @@ public class ManageApplications extends Fragment implements
}
}
- private int getIndex(int listType) {
- for (int i = 0; i < mIndexToType.size(); i++) {
- if (listType == mIndexToType.get(i)) return i;
+ TabInfo tabForType(int type) {
+ for (int i = 0; i < mTabs.size(); i++) {
+ TabInfo tab = mTabs.get(i);
+ if (tab.mListType == type) {
+ return tab;
+ }
}
- return 0;
+ return null;
}
// utility method used to start sub activity
@@ -771,9 +992,10 @@ public class ManageApplications extends Fragment implements
* The running processes screen doesn't use the mApplicationsAdapter
* so bringing up this menu in that case doesn't make any sense.
*/
- if (mCurView == VIEW_RUNNING) {
- boolean showingBackground = mRunningProcessesView != null
- ? mRunningProcessesView.mAdapter.getShowBackground() : false;
+ if (mCurTab != null && mCurTab.mListType == LIST_TYPE_RUNNING) {
+ TabInfo tab = tabForType(LIST_TYPE_RUNNING);
+ boolean showingBackground = tab != null && tab.mRunningProcessesView != null
+ ? tab.mRunningProcessesView.mAdapter.getShowBackground() : false;
mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(false);
mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(false);
mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(showingBackground);
@@ -861,8 +1083,15 @@ public class ManageApplications extends Fragment implements
if (DEBUG) Log.v(TAG, "Done clearing");
if (getActivity() != null && mActivityResumed) {
if (DEBUG) Log.v(TAG, "Updating UI!");
- mApplicationsAdapter.pause();
- showCurrentList();
+ for (int i=0; i<mTabs.size(); i++) {
+ TabInfo tab = mTabs.get(i);
+ if (tab.mApplications != null) {
+ tab.mApplications.pause();
+ }
+ }
+ if (mCurTab != null) {
+ mCurTab.resume(mSortOrder);
+ }
}
}
});
@@ -877,15 +1106,19 @@ public class ManageApplications extends Fragment implements
int menuId = item.getItemId();
if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
mSortOrder = menuId;
- if (mCurView != VIEW_RUNNING) {
- mApplicationsAdapter.rebuild(mFilterApps, mSortOrder);
+ if (mCurTab != null && mCurTab.mApplications != null) {
+ mCurTab.mApplications.rebuild(mSortOrder);
}
} else if (menuId == SHOW_RUNNING_SERVICES) {
mShowBackground = false;
- mRunningProcessesView.mAdapter.setShowBackground(false);
+ if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
+ mCurTab.mRunningProcessesView.mAdapter.setShowBackground(false);
+ }
} else if (menuId == SHOW_BACKGROUND_PROCESSES) {
mShowBackground = true;
- mRunningProcessesView.mAdapter.setShowBackground(true);
+ if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
+ mCurTab.mRunningProcessesView.mAdapter.setShowBackground(true);
+ }
} else if (menuId == RESET_APP_PREFERENCES) {
buildResetDialog();
} else {
@@ -898,199 +1131,48 @@ public class ManageApplications extends Fragment implements
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
- ApplicationsState.AppEntry entry = mApplicationsAdapter.getAppEntry(position);
- mCurrentPkgName = entry.info.packageName;
- startApplicationDetailsActivity();
- }
-
- static final int VIEW_NOTHING = 0;
- static final int VIEW_LIST = 1;
- static final int VIEW_RUNNING = 2;
-
- void updateStorageUsage() {
- // Fragment view not yet created?
- if (mRootView == null) return;
- // Make sure a callback didn't come at an inopportune time.
- if (getActivity() == null) return;
-
- if (mCurView == VIEW_RUNNING) {
- return;
+ if (mCurTab != null && mCurTab.mApplications != null) {
+ ApplicationsState.AppEntry entry = mCurTab.mApplications.getAppEntry(position);
+ mCurrentPkgName = entry.info.packageName;
+ startApplicationDetailsActivity();
}
+ }
- long freeStorage = 0;
- long appStorage = 0;
- long totalStorage = 0;
- CharSequence newLabel = null;
-
- if (mFilterApps == FILTER_APPS_SDCARD) {
- if (mLastShowedInternalStorage) {
- mLastShowedInternalStorage = false;
- }
- newLabel = getActivity().getText(R.string.sd_card_storage);
-
- if (mContainerService != null) {
- try {
- final long[] stats = mContainerService.getFileSystemStats(
- Environment.getExternalStorageDirectory().getPath());
- totalStorage = stats[0];
- freeStorage = stats[1];
- } catch (RemoteException e) {
- Log.w(TAG, "Problem in container service", e);
- }
- }
+ public void updateCurrentTab(int position) {
+ TabInfo tab = mTabs.get(position);
+ mCurTab = tab;
- final int N = mApplicationsAdapter.getCount();
- for (int i=0; i<N; i++) {
- ApplicationsState.AppEntry ae = mApplicationsAdapter.getAppEntry(i);
- appStorage += ae.externalCodeSize + ae.externalDataSize;
- }
+ // Put things in the correct paused/resumed state.
+ if (mActivityResumed) {
+ mCurTab.build(mInflater, mContentContainer, mRootView);
+ mCurTab.resume(mSortOrder);
} else {
- if (!mLastShowedInternalStorage) {
- mLastShowedInternalStorage = true;
- }
- newLabel = getActivity().getText(R.string.internal_storage);
-
- if (mContainerService != null) {
- try {
- final long[] stats = mContainerService.getFileSystemStats(
- Environment.getDataDirectory().getPath());
- totalStorage = stats[0];
- freeStorage = stats[1];
- } catch (RemoteException e) {
- Log.w(TAG, "Problem in container service", e);
- }
- }
-
- final boolean emulatedStorage = Environment.isExternalStorageEmulated();
- final int N = mApplicationsAdapter.getCount();
- for (int i=0; i<N; i++) {
- ApplicationsState.AppEntry ae = mApplicationsAdapter.getAppEntry(i);
- appStorage += ae.codeSize + ae.dataSize;
- if (emulatedStorage) {
- appStorage += ae.externalCodeSize + ae.externalDataSize;
- }
- }
- freeStorage += mApplicationsState.sumCacheSizes();
+ mCurTab.pause();
}
- if (newLabel != null) {
- mStorageChartLabel.setText(newLabel);
- }
- if (totalStorage > 0) {
- mColorBar.setRatios((totalStorage-freeStorage-appStorage)/(float)totalStorage,
- appStorage/(float)totalStorage, freeStorage/(float)totalStorage);
- long usedStorage = totalStorage - freeStorage;
- if (mLastUsedStorage != usedStorage) {
- mLastUsedStorage = usedStorage;
- String sizeStr = Formatter.formatShortFileSize(getActivity(), usedStorage);
- mUsedStorageText.setText(getActivity().getResources().getString(
- R.string.service_foreground_processes, sizeStr));
- }
- if (mLastFreeStorage != freeStorage) {
- mLastFreeStorage = freeStorage;
- String sizeStr = Formatter.formatShortFileSize(getActivity(), freeStorage);
- mFreeStorageText.setText(getActivity().getResources().getString(
- R.string.service_background_processes, sizeStr));
- }
- } else {
- mColorBar.setRatios(0, 0, 0);
- if (mLastUsedStorage != -1) {
- mLastUsedStorage = -1;
- mUsedStorageText.setText("");
- }
- if (mLastFreeStorage != -1) {
- mLastFreeStorage = -1;
- mFreeStorageText.setText("");
+ for (int i=0; i<mTabs.size(); i++) {
+ TabInfo t = mTabs.get(i);
+ if (t != mCurTab) {
+ t.pause();
}
}
- }
- private void selectView(int which) {
- if (which == VIEW_LIST) {
- if (mResumedRunning) {
- mRunningProcessesView.doPause();
- mResumedRunning = false;
- }
- if (mCurView != which) {
- mRunningProcessesView.setVisibility(View.GONE);
- mListContainer.setVisibility(View.VISIBLE);
- mLoadingContainer.setVisibility(View.GONE);
- }
- if (mActivityResumed) {
- mApplicationsAdapter.resume(mFilterApps, mSortOrder);
- }
- } else if (which == VIEW_RUNNING) {
- if (!mCreatedRunning) {
- mRunningProcessesView.doCreate(null);
- mRunningProcessesView.mAdapter.setShowBackground(mShowBackground);
- mCreatedRunning = true;
- }
- boolean haveData = true;
- if (mActivityResumed && !mResumedRunning) {
- haveData = mRunningProcessesView.doResume(this, mRunningProcessesAvail);
- mResumedRunning = true;
- }
- mApplicationsAdapter.pause();
- if (mCurView != which) {
- if (haveData) {
- mRunningProcessesView.setVisibility(View.VISIBLE);
- } else {
- mLoadingContainer.setVisibility(View.VISIBLE);
- }
- mListContainer.setVisibility(View.GONE);
- }
- }
- mCurView = which;
+ mCurTab.updateStorageUsage();
+ updateOptionsMenu();
final Activity host = getActivity();
if (host != null) {
host.invalidateOptionsMenu();
}
}
- void handleRunningProcessesAvail() {
- if (mCurView == VIEW_RUNNING) {
- mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
- getActivity(), android.R.anim.fade_out));
- mRunningProcessesView.startAnimation(AnimationUtils.loadAnimation(
- getActivity(), android.R.anim.fade_in));
- mRunningProcessesView.setVisibility(View.VISIBLE);
- mLoadingContainer.setVisibility(View.GONE);
- }
- }
-
- public void showCurrentList() {
- int listType = mIndexToType.get(mSpinner.getSelectedItemPosition());
-
- int newOption;
- if (LIST_TYPE_DOWNLOADED == listType) {
- newOption = FILTER_APPS_THIRD_PARTY;
- } else if (LIST_TYPE_ALL == listType) {
- newOption = FILTER_APPS_ALL;
- } else if (LIST_TYPE_SDCARD == listType) {
- newOption = FILTER_APPS_SDCARD;
- } else if (LIST_TYPE_RUNNING == listType) {
- ((InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE))
- .hideSoftInputFromWindow(
- getActivity().getWindow().getDecorView().getWindowToken(), 0);
- selectView(VIEW_RUNNING);
- return;
- } else {
- // Invalid option. Do nothing
- return;
- }
-
- mFilterApps = newOption;
- selectView(VIEW_LIST);
- updateStorageUsage();
- updateOptionsMenu();
- }
-
private volatile IMediaContainerService mContainerService;
private final ServiceConnection mContainerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mContainerService = IMediaContainerService.Stub.asInterface(service);
- updateStorageUsage();
+ if (mCurTab != null) {
+ mCurTab.updateStorageUsage();
+ }
}
@Override