diff options
author | Dianne Hackborn <hackbod@google.com> | 2012-05-16 15:50:48 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2012-05-16 19:31:07 -0700 |
commit | 309c5dcee18ced447d049d5de882a9586694e04c (patch) | |
tree | 31b8df7f153df3a20909b2c46698f6c6be653e11 | |
parent | 1cbacf10bd525c8f467b37abc57085b071abd6de (diff) | |
download | packages_apps_Settings-309c5dcee18ced447d049d5de882a9586694e04c.zip packages_apps_Settings-309c5dcee18ced447d049d5de882a9586694e04c.tar.gz packages_apps_Settings-309c5dcee18ced447d049d5de882a9586694e04c.tar.bz2 |
Rework manage applications to be page-able.
Turn everything around so that we can have multiple list views
with their own adapters. Switch to using a ViewPager for managing
the different lists. Smile!
Change-Id: I9c102abb06cf67f313a8696507aa4597b38c7ab9
-rw-r--r-- | Android.mk | 2 | ||||
-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.xml | 41 | ||||
-rw-r--r-- | res/layout/manage_applications_running.xml | 47 | ||||
-rw-r--r-- | res/layout/manage_apps_spinner_content.xml | 51 | ||||
-rw-r--r-- | src/com/android/settings/applications/AppViewHolder.java | 4 | ||||
-rw-r--r-- | src/com/android/settings/applications/ApplicationsState.java | 389 | ||||
-rw-r--r-- | src/com/android/settings/applications/InstalledAppDetails.java | 6 | ||||
-rw-r--r-- | src/com/android/settings/applications/ManageApplications.java | 744 |
9 files changed, 754 insertions, 540 deletions
@@ -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 |