• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.applications;
18 
19 import static android.net.NetworkPolicyManager.POLICY_NONE;
20 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
21 
22 import android.app.Activity;
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.AppOpsManager;
26 import android.app.Fragment;
27 import android.app.INotificationManager;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.ServiceConnection;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.IPackageManager;
36 import android.content.pm.PackageInfo;
37 import android.content.pm.PackageManager;
38 import android.net.NetworkPolicyManager;
39 import android.os.AsyncTask;
40 import android.os.Bundle;
41 import android.os.Environment;
42 import android.os.Handler;
43 import android.os.IBinder;
44 import android.os.RemoteException;
45 import android.os.ServiceManager;
46 import android.os.UserHandle;
47 import android.preference.PreferenceActivity;
48 import android.preference.PreferenceFrameLayout;
49 import android.provider.Settings;
50 import android.support.v4.view.PagerAdapter;
51 import android.support.v4.view.PagerTabStrip;
52 import android.support.v4.view.ViewPager;
53 import android.text.format.Formatter;
54 import android.util.Log;
55 import android.view.LayoutInflater;
56 import android.view.Menu;
57 import android.view.MenuInflater;
58 import android.view.MenuItem;
59 import android.view.View;
60 import android.view.ViewGroup;
61 import android.view.animation.AnimationUtils;
62 import android.widget.AbsListView;
63 import android.widget.AdapterView;
64 import android.widget.AdapterView.OnItemClickListener;
65 import android.widget.BaseAdapter;
66 import android.widget.Filter;
67 import android.widget.Filterable;
68 import android.widget.ListView;
69 import android.widget.TextView;
70 
71 import com.android.internal.app.IMediaContainerService;
72 import com.android.internal.content.PackageHelper;
73 import com.android.settings.R;
74 import com.android.settings.Settings.RunningServicesActivity;
75 import com.android.settings.Settings.StorageUseActivity;
76 import com.android.settings.applications.ApplicationsState.AppEntry;
77 import com.android.settings.deviceinfo.StorageMeasurement;
78 import com.android.settings.Utils;
79 
80 import java.util.ArrayList;
81 import java.util.Comparator;
82 import java.util.List;
83 
84 final class CanBeOnSdCardChecker {
85     final IPackageManager mPm;
86     int mInstallLocation;
87 
CanBeOnSdCardChecker()88     CanBeOnSdCardChecker() {
89         mPm = IPackageManager.Stub.asInterface(
90                 ServiceManager.getService("package"));
91     }
92 
init()93     void init() {
94         try {
95             mInstallLocation = mPm.getInstallLocation();
96         } catch (RemoteException e) {
97             Log.e("CanBeOnSdCardChecker", "Is Package Manager running?");
98             return;
99         }
100     }
101 
check(ApplicationInfo info)102     boolean check(ApplicationInfo info) {
103         boolean canBe = false;
104         if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
105             canBe = true;
106         } else {
107             if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
108                 if (info.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL ||
109                         info.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
110                     canBe = true;
111                 } else if (info.installLocation
112                         == PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
113                     if (mInstallLocation == PackageHelper.APP_INSTALL_EXTERNAL) {
114                         // For apps with no preference and the default value set
115                         // to install on sdcard.
116                         canBe = true;
117                     }
118                 }
119             }
120         }
121         return canBe;
122     }
123 }
124 
125 interface AppClickListener {
onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent, View view, int position, long id)126     void onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent,
127             View view, int position, long id);
128 }
129 
130 /**
131  * Activity to pick an application that will be used to display installation information and
132  * options to uninstall/delete user data for system applications. This activity
133  * can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE
134  * intent.
135  */
136 public class ManageApplications extends Fragment implements
137         AppClickListener, DialogInterface.OnClickListener,
138         DialogInterface.OnDismissListener {
139 
140     static final String TAG = "ManageApplications";
141     static final boolean DEBUG = false;
142 
143     private static final String EXTRA_SORT_ORDER = "sortOrder";
144     private static final String EXTRA_SHOW_BACKGROUND = "showBackground";
145     private static final String EXTRA_DEFAULT_LIST_TYPE = "defaultListType";
146     private static final String EXTRA_RESET_DIALOG = "resetDialog";
147 
148     // attributes used as keys when passing values to InstalledAppDetails activity
149     public static final String APP_CHG = "chg";
150 
151     // constant value that can be used to check return code from sub activity.
152     private static final int INSTALLED_APP_DETAILS = 1;
153 
154     public static final int SIZE_TOTAL = 0;
155     public static final int SIZE_INTERNAL = 1;
156     public static final int SIZE_EXTERNAL = 2;
157 
158     // sort order that can be changed through the menu can be sorted alphabetically
159     // or size(descending)
160     private static final int MENU_OPTIONS_BASE = 0;
161     // Filter options used for displayed list of applications
162     public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 0;
163     public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 1;
164     public static final int FILTER_APPS_SDCARD = MENU_OPTIONS_BASE + 2;
165     public static final int FILTER_APPS_DISABLED = MENU_OPTIONS_BASE + 3;
166 
167     public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 4;
168     public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 5;
169     public static final int SHOW_RUNNING_SERVICES = MENU_OPTIONS_BASE + 6;
170     public static final int SHOW_BACKGROUND_PROCESSES = MENU_OPTIONS_BASE + 7;
171     public static final int RESET_APP_PREFERENCES = MENU_OPTIONS_BASE + 8;
172     // sort order
173     private int mSortOrder = SORT_ORDER_ALPHA;
174 
175     private ApplicationsState mApplicationsState;
176 
177     public static class TabInfo implements OnItemClickListener {
178         public final ManageApplications mOwner;
179         public final ApplicationsState mApplicationsState;
180         public final CharSequence mLabel;
181         public final int mListType;
182         public final int mFilter;
183         public final AppClickListener mClickListener;
184         public final CharSequence mInvalidSizeStr;
185         public final CharSequence mComputingSizeStr;
186         private final Bundle mSavedInstanceState;
187 
188         public ApplicationsAdapter mApplications;
189         public LayoutInflater mInflater;
190         public View mRootView;
191 
192         private IMediaContainerService mContainerService;
193 
194         private View mLoadingContainer;
195 
196         private View mListContainer;
197 
198         // ListView used to display list
199         private ListView mListView;
200         // Custom view used to display running processes
201         private RunningProcessesView mRunningProcessesView;
202 
203         private LinearColorBar mColorBar;
204         private TextView mStorageChartLabel;
205         private TextView mUsedStorageText;
206         private TextView mFreeStorageText;
207         private long mFreeStorage = 0, mAppStorage = 0, mTotalStorage = 0;
208         private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
209 
210         final Runnable mRunningProcessesAvail = new Runnable() {
211             public void run() {
212                 handleRunningProcessesAvail();
213             }
214         };
215 
TabInfo(ManageApplications owner, ApplicationsState apps, CharSequence label, int listType, AppClickListener clickListener, Bundle savedInstanceState)216         public TabInfo(ManageApplications owner, ApplicationsState apps,
217                 CharSequence label, int listType, AppClickListener clickListener,
218                 Bundle savedInstanceState) {
219             mOwner = owner;
220             mApplicationsState = apps;
221             mLabel = label;
222             mListType = listType;
223             switch (listType) {
224                 case LIST_TYPE_DOWNLOADED: mFilter = FILTER_APPS_THIRD_PARTY; break;
225                 case LIST_TYPE_SDCARD: mFilter = FILTER_APPS_SDCARD; break;
226                 case LIST_TYPE_DISABLED: mFilter = FILTER_APPS_DISABLED; break;
227                 default: mFilter = FILTER_APPS_ALL; break;
228             }
229             mClickListener = clickListener;
230             mInvalidSizeStr = owner.getActivity().getText(R.string.invalid_size_value);
231             mComputingSizeStr = owner.getActivity().getText(R.string.computing_size);
232             mSavedInstanceState = savedInstanceState;
233         }
234 
setContainerService(IMediaContainerService containerService)235         public void setContainerService(IMediaContainerService containerService) {
236             mContainerService = containerService;
237             updateStorageUsage();
238         }
239 
build(LayoutInflater inflater, ViewGroup contentParent, View contentChild)240         public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
241             if (mRootView != null) {
242                 return mRootView;
243             }
244 
245             mInflater = inflater;
246             mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING
247                     ? R.layout.manage_applications_running
248                     : R.layout.manage_applications_apps, null);
249             mLoadingContainer = mRootView.findViewById(R.id.loading_container);
250             mLoadingContainer.setVisibility(View.VISIBLE);
251             mListContainer = mRootView.findViewById(R.id.list_container);
252             if (mListContainer != null) {
253                 // Create adapter and list view here
254                 View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
255                 ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
256                 if (emptyView != null) {
257                     lv.setEmptyView(emptyView);
258                 }
259                 lv.setOnItemClickListener(this);
260                 lv.setSaveEnabled(true);
261                 lv.setItemsCanFocus(true);
262                 lv.setTextFilterEnabled(true);
263                 mListView = lv;
264                 mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
265                 mListView.setAdapter(mApplications);
266                 mListView.setRecyclerListener(mApplications);
267                 mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
268                 mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
269                 mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
270                 mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
271                 Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
272                 if (mFilter == FILTER_APPS_SDCARD) {
273                     mStorageChartLabel.setText(mOwner.getActivity().getText(
274                             R.string.sd_card_storage));
275                 } else {
276                     mStorageChartLabel.setText(mOwner.getActivity().getText(
277                             R.string.internal_storage));
278                 }
279                 applyCurrentStorage();
280             }
281             mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
282                     R.id.running_processes);
283             if (mRunningProcessesView != null) {
284                 mRunningProcessesView.doCreate(mSavedInstanceState);
285             }
286 
287             return mRootView;
288         }
289 
detachView()290         public void detachView() {
291             if (mRootView != null) {
292                 ViewGroup group = (ViewGroup)mRootView.getParent();
293                 if (group != null) {
294                     group.removeView(mRootView);
295                 }
296             }
297         }
298 
resume(int sortOrder)299         public void resume(int sortOrder) {
300             if (mApplications != null) {
301                 mApplications.resume(sortOrder);
302             }
303             if (mRunningProcessesView != null) {
304                 boolean haveData = mRunningProcessesView.doResume(mOwner, mRunningProcessesAvail);
305                 if (haveData) {
306                     mRunningProcessesView.setVisibility(View.VISIBLE);
307                     mLoadingContainer.setVisibility(View.INVISIBLE);
308                 } else {
309                     mLoadingContainer.setVisibility(View.VISIBLE);
310                 }
311             }
312         }
313 
pause()314         public void pause() {
315             if (mApplications != null) {
316                 mApplications.pause();
317             }
318             if (mRunningProcessesView != null) {
319                 mRunningProcessesView.doPause();
320             }
321         }
322 
updateStorageUsage()323         void updateStorageUsage() {
324             // Make sure a callback didn't come at an inopportune time.
325             if (mOwner.getActivity() == null) return;
326             // Doesn't make sense for stuff that is not an app list.
327             if (mApplications == null) return;
328 
329             mFreeStorage = 0;
330             mAppStorage = 0;
331             mTotalStorage = 0;
332 
333             if (mFilter == FILTER_APPS_SDCARD) {
334                 if (mContainerService != null) {
335                     try {
336                         final long[] stats = mContainerService.getFileSystemStats(
337                                 Environment.getExternalStorageDirectory().getPath());
338                         mTotalStorage = stats[0];
339                         mFreeStorage = stats[1];
340                     } catch (RemoteException e) {
341                         Log.w(TAG, "Problem in container service", e);
342                     }
343                 }
344 
345                 if (mApplications != null) {
346                     final int N = mApplications.getCount();
347                     for (int i=0; i<N; i++) {
348                         ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
349                         mAppStorage += ae.externalCodeSize + ae.externalDataSize
350                                 + ae.externalCacheSize;
351                     }
352                 }
353             } else {
354                 if (mContainerService != null) {
355                     try {
356                         final long[] stats = mContainerService.getFileSystemStats(
357                                 Environment.getDataDirectory().getPath());
358                         mTotalStorage = stats[0];
359                         mFreeStorage = stats[1];
360                     } catch (RemoteException e) {
361                         Log.w(TAG, "Problem in container service", e);
362                     }
363                 }
364 
365                 final boolean emulatedStorage = Environment.isExternalStorageEmulated();
366                 if (mApplications != null) {
367                     final int N = mApplications.getCount();
368                     for (int i=0; i<N; i++) {
369                         ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
370                         mAppStorage += ae.codeSize + ae.dataSize;
371                         if (emulatedStorage) {
372                             mAppStorage += ae.externalCodeSize + ae.externalDataSize;
373                         }
374                     }
375                 }
376                 mFreeStorage += mApplicationsState.sumCacheSizes();
377             }
378 
379             applyCurrentStorage();
380         }
381 
applyCurrentStorage()382         void applyCurrentStorage() {
383             // If view hierarchy is not yet created, no views to update.
384             if (mRootView == null) {
385                 return;
386             }
387             if (mTotalStorage > 0) {
388                 mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage,
389                         mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage);
390                 long usedStorage = mTotalStorage - mFreeStorage;
391                 if (mLastUsedStorage != usedStorage) {
392                     mLastUsedStorage = usedStorage;
393                     String sizeStr = Formatter.formatShortFileSize(
394                             mOwner.getActivity(), usedStorage);
395                     mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
396                             R.string.service_foreground_processes, sizeStr));
397                 }
398                 if (mLastFreeStorage != mFreeStorage) {
399                     mLastFreeStorage = mFreeStorage;
400                     String sizeStr = Formatter.formatShortFileSize(
401                             mOwner.getActivity(), mFreeStorage);
402                     mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
403                             R.string.service_background_processes, sizeStr));
404                 }
405             } else {
406                 mColorBar.setRatios(0, 0, 0);
407                 if (mLastUsedStorage != -1) {
408                     mLastUsedStorage = -1;
409                     mUsedStorageText.setText("");
410                 }
411                 if (mLastFreeStorage != -1) {
412                     mLastFreeStorage = -1;
413                     mFreeStorageText.setText("");
414                 }
415             }
416         }
417 
418         @Override
onItemClick(AdapterView<?> parent, View view, int position, long id)419         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
420             mClickListener.onItemClick(this, parent, view, position, id);
421         }
422 
handleRunningProcessesAvail()423         void handleRunningProcessesAvail() {
424             mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
425                     mOwner.getActivity(), android.R.anim.fade_out));
426             mRunningProcessesView.startAnimation(AnimationUtils.loadAnimation(
427                     mOwner.getActivity(), android.R.anim.fade_in));
428             mRunningProcessesView.setVisibility(View.VISIBLE);
429             mLoadingContainer.setVisibility(View.GONE);
430         }
431     }
432     private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
433     private int mNumTabs;
434     TabInfo mCurTab = null;
435 
436     // Size resource used for packages whose size computation failed for some reason
437     CharSequence mInvalidSizeStr;
438     private CharSequence mComputingSizeStr;
439 
440     // layout inflater object used to inflate views
441     private LayoutInflater mInflater;
442 
443     private String mCurrentPkgName;
444 
445     private Menu mOptionsMenu;
446 
447     // These are for keeping track of activity and spinner switch state.
448     private boolean mActivityResumed;
449 
450     static final int LIST_TYPE_DOWNLOADED = 0;
451     static final int LIST_TYPE_RUNNING = 1;
452     static final int LIST_TYPE_SDCARD = 2;
453     static final int LIST_TYPE_ALL = 3;
454     static final int LIST_TYPE_DISABLED = 4;
455 
456     private boolean mShowBackground = false;
457 
458     private int mDefaultListType = -1;
459 
460     private ViewGroup mContentContainer;
461     private View mRootView;
462     private ViewPager mViewPager;
463 
464     AlertDialog mResetDialog;
465 
466     class MyPagerAdapter extends PagerAdapter
467             implements ViewPager.OnPageChangeListener {
468         int mCurPos = 0;
469 
470         @Override
getCount()471         public int getCount() {
472             return mNumTabs;
473         }
474 
475         @Override
instantiateItem(ViewGroup container, int position)476         public Object instantiateItem(ViewGroup container, int position) {
477             TabInfo tab = mTabs.get(position);
478             View root = tab.build(mInflater, mContentContainer, mRootView);
479             container.addView(root);
480             root.setTag(R.id.name, tab);
481             return root;
482         }
483 
484         @Override
destroyItem(ViewGroup container, int position, Object object)485         public void destroyItem(ViewGroup container, int position, Object object) {
486             container.removeView((View)object);
487         }
488 
489         @Override
isViewFromObject(View view, Object object)490         public boolean isViewFromObject(View view, Object object) {
491             return view == object;
492         }
493 
494         @Override
getItemPosition(Object object)495         public int getItemPosition(Object object) {
496             return super.getItemPosition(object);
497             //return ((TabInfo)((View)object).getTag(R.id.name)).mListType;
498         }
499 
500         @Override
getPageTitle(int position)501         public CharSequence getPageTitle(int position) {
502             return mTabs.get(position).mLabel;
503         }
504 
505         @Override
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)506         public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
507         }
508 
509         @Override
onPageSelected(int position)510         public void onPageSelected(int position) {
511             mCurPos = position;
512         }
513 
514         @Override
onPageScrollStateChanged(int state)515         public void onPageScrollStateChanged(int state) {
516             if (state == ViewPager.SCROLL_STATE_IDLE) {
517                 updateCurrentTab(mCurPos);
518             }
519         }
520     }
521 
522     /*
523      * Custom adapter implementation for the ListView
524      * This adapter maintains a map for each displayed application and its properties
525      * An index value on each AppInfo object indicates the correct position or index
526      * in the list. If the list gets updated dynamically when the user is viewing the list of
527      * applications, we need to return the correct index of position. This is done by mapping
528      * the getId methods via the package name into the internal maps and indices.
529      * The order of applications in the list is mirrored in mAppLocalList
530      */
531     static class ApplicationsAdapter extends BaseAdapter implements Filterable,
532             ApplicationsState.Callbacks, AbsListView.RecyclerListener {
533         private final ApplicationsState mState;
534         private final ApplicationsState.Session mSession;
535         private final TabInfo mTab;
536         private final Context mContext;
537         private final ArrayList<View> mActive = new ArrayList<View>();
538         private final int mFilterMode;
539         private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
540         private ArrayList<ApplicationsState.AppEntry> mEntries;
541         private boolean mResumed;
542         private int mLastSortMode=-1;
543         private boolean mWaitingForData;
544         private int mWhichSize = SIZE_TOTAL;
545         CharSequence mCurFilterPrefix;
546 
547         private Filter mFilter = new Filter() {
548             @Override
549             protected FilterResults performFiltering(CharSequence constraint) {
550                 ArrayList<ApplicationsState.AppEntry> entries
551                         = applyPrefixFilter(constraint, mBaseEntries);
552                 FilterResults fr = new FilterResults();
553                 fr.values = entries;
554                 fr.count = entries.size();
555                 return fr;
556             }
557 
558             @Override
559             protected void publishResults(CharSequence constraint, FilterResults results) {
560                 mCurFilterPrefix = constraint;
561                 mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values;
562                 notifyDataSetChanged();
563                 mTab.updateStorageUsage();
564             }
565         };
566 
ApplicationsAdapter(ApplicationsState state, TabInfo tab, int filterMode)567         public ApplicationsAdapter(ApplicationsState state, TabInfo tab, int filterMode) {
568             mState = state;
569             mSession = state.newSession(this);
570             mTab = tab;
571             mContext = tab.mOwner.getActivity();
572             mFilterMode = filterMode;
573         }
574 
resume(int sort)575         public void resume(int sort) {
576             if (DEBUG) Log.i(TAG, "Resume!  mResumed=" + mResumed);
577             if (!mResumed) {
578                 mResumed = true;
579                 mSession.resume();
580                 mLastSortMode = sort;
581                 rebuild(true);
582             } else {
583                 rebuild(sort);
584             }
585         }
586 
pause()587         public void pause() {
588             if (mResumed) {
589                 mResumed = false;
590                 mSession.pause();
591             }
592         }
593 
rebuild(int sort)594         public void rebuild(int sort) {
595             if (sort == mLastSortMode) {
596                 return;
597             }
598             mLastSortMode = sort;
599             rebuild(true);
600         }
601 
rebuild(boolean eraseold)602         public void rebuild(boolean eraseold) {
603             if (DEBUG) Log.i(TAG, "Rebuilding app list...");
604             ApplicationsState.AppFilter filterObj;
605             Comparator<AppEntry> comparatorObj;
606             boolean emulated = Environment.isExternalStorageEmulated();
607             if (emulated) {
608                 mWhichSize = SIZE_TOTAL;
609             } else {
610                 mWhichSize = SIZE_INTERNAL;
611             }
612             switch (mFilterMode) {
613                 case FILTER_APPS_THIRD_PARTY:
614                     filterObj = ApplicationsState.THIRD_PARTY_FILTER;
615                     break;
616                 case FILTER_APPS_SDCARD:
617                     filterObj = ApplicationsState.ON_SD_CARD_FILTER;
618                     if (!emulated) {
619                         mWhichSize = SIZE_EXTERNAL;
620                     }
621                     break;
622                 case FILTER_APPS_DISABLED:
623                     filterObj = ApplicationsState.DISABLED_FILTER;
624                     break;
625                 default:
626                     filterObj = ApplicationsState.ALL_ENABLED_FILTER;
627                     break;
628             }
629             switch (mLastSortMode) {
630                 case SORT_ORDER_SIZE:
631                     switch (mWhichSize) {
632                         case SIZE_INTERNAL:
633                             comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR;
634                             break;
635                         case SIZE_EXTERNAL:
636                             comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR;
637                             break;
638                         default:
639                             comparatorObj = ApplicationsState.SIZE_COMPARATOR;
640                             break;
641                     }
642                     break;
643                 default:
644                     comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
645                     break;
646             }
647             ArrayList<ApplicationsState.AppEntry> entries
648                     = mSession.rebuild(filterObj, comparatorObj);
649             if (entries == null && !eraseold) {
650                 // Don't have new list yet, but can continue using the old one.
651                 return;
652             }
653             mBaseEntries = entries;
654             if (mBaseEntries != null) {
655                 mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
656             } else {
657                 mEntries = null;
658             }
659             notifyDataSetChanged();
660             mTab.updateStorageUsage();
661 
662             if (entries == null) {
663                 mWaitingForData = true;
664                 mTab.mListContainer.setVisibility(View.INVISIBLE);
665                 mTab.mLoadingContainer.setVisibility(View.VISIBLE);
666             } else {
667                 mTab.mListContainer.setVisibility(View.VISIBLE);
668                 mTab.mLoadingContainer.setVisibility(View.GONE);
669             }
670         }
671 
applyPrefixFilter(CharSequence prefix, ArrayList<ApplicationsState.AppEntry> origEntries)672         ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
673                 ArrayList<ApplicationsState.AppEntry> origEntries) {
674             if (prefix == null || prefix.length() == 0) {
675                 return origEntries;
676             } else {
677                 String prefixStr = ApplicationsState.normalize(prefix.toString());
678                 final String spacePrefixStr = " " + prefixStr;
679                 ArrayList<ApplicationsState.AppEntry> newEntries
680                         = new ArrayList<ApplicationsState.AppEntry>();
681                 for (int i=0; i<origEntries.size(); i++) {
682                     ApplicationsState.AppEntry entry = origEntries.get(i);
683                     String nlabel = entry.getNormalizedLabel();
684                     if (nlabel.startsWith(prefixStr) || nlabel.indexOf(spacePrefixStr) != -1) {
685                         newEntries.add(entry);
686                     }
687                 }
688                 return newEntries;
689             }
690         }
691 
692         @Override
onRunningStateChanged(boolean running)693         public void onRunningStateChanged(boolean running) {
694             mTab.mOwner.getActivity().setProgressBarIndeterminateVisibility(running);
695         }
696 
697         @Override
onRebuildComplete(ArrayList<AppEntry> apps)698         public void onRebuildComplete(ArrayList<AppEntry> apps) {
699             if (mTab.mLoadingContainer.getVisibility() == View.VISIBLE) {
700                 mTab.mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
701                         mContext, android.R.anim.fade_out));
702                 mTab.mListContainer.startAnimation(AnimationUtils.loadAnimation(
703                         mContext, android.R.anim.fade_in));
704             }
705             mTab.mListContainer.setVisibility(View.VISIBLE);
706             mTab.mLoadingContainer.setVisibility(View.GONE);
707             mWaitingForData = false;
708             mBaseEntries = apps;
709             mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
710             notifyDataSetChanged();
711             mTab.updateStorageUsage();
712         }
713 
714         @Override
onPackageListChanged()715         public void onPackageListChanged() {
716             rebuild(false);
717         }
718 
719         @Override
onPackageIconChanged()720         public void onPackageIconChanged() {
721             // We ensure icons are loaded when their item is displayed, so
722             // don't care about icons loaded in the background.
723         }
724 
725         @Override
onPackageSizeChanged(String packageName)726         public void onPackageSizeChanged(String packageName) {
727             for (int i=0; i<mActive.size(); i++) {
728                 AppViewHolder holder = (AppViewHolder)mActive.get(i).getTag();
729                 if (holder.entry.info.packageName.equals(packageName)) {
730                     synchronized (holder.entry) {
731                         holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
732                     }
733                     if (holder.entry.info.packageName.equals(mTab.mOwner.mCurrentPkgName)
734                             && mLastSortMode == SORT_ORDER_SIZE) {
735                         // We got the size information for the last app the
736                         // user viewed, and are sorting by size...  they may
737                         // have cleared data, so we immediately want to resort
738                         // the list with the new size to reflect it to the user.
739                         rebuild(false);
740                     }
741                     mTab.updateStorageUsage();
742                     return;
743                 }
744             }
745         }
746 
747         @Override
onAllSizesComputed()748         public void onAllSizesComputed() {
749             if (mLastSortMode == SORT_ORDER_SIZE) {
750                 rebuild(false);
751             }
752             mTab.updateStorageUsage();
753         }
754 
getCount()755         public int getCount() {
756             return mEntries != null ? mEntries.size() : 0;
757         }
758 
getItem(int position)759         public Object getItem(int position) {
760             return mEntries.get(position);
761         }
762 
getAppEntry(int position)763         public ApplicationsState.AppEntry getAppEntry(int position) {
764             return mEntries.get(position);
765         }
766 
getItemId(int position)767         public long getItemId(int position) {
768             return mEntries.get(position).id;
769         }
770 
getView(int position, View convertView, ViewGroup parent)771         public View getView(int position, View convertView, ViewGroup parent) {
772             // A ViewHolder keeps references to children views to avoid unnecessary calls
773             // to findViewById() on each row.
774             AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView);
775             convertView = holder.rootView;
776 
777             // Bind the data efficiently with the holder
778             ApplicationsState.AppEntry entry = mEntries.get(position);
779             synchronized (entry) {
780                 holder.entry = entry;
781                 if (entry.label != null) {
782                     holder.appName.setText(entry.label);
783                 }
784                 mState.ensureIcon(entry);
785                 if (entry.icon != null) {
786                     holder.appIcon.setImageDrawable(entry.icon);
787                 }
788                 holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
789                 if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
790                     holder.disabled.setVisibility(View.VISIBLE);
791                     holder.disabled.setText(R.string.not_installed);
792                 } else if (!entry.info.enabled) {
793                     holder.disabled.setVisibility(View.VISIBLE);
794                     holder.disabled.setText(R.string.disabled);
795                 } else {
796                     holder.disabled.setVisibility(View.GONE);
797                 }
798                 if (mFilterMode == FILTER_APPS_SDCARD) {
799                     holder.checkBox.setVisibility(View.VISIBLE);
800                     holder.checkBox.setChecked((entry.info.flags
801                             & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
802                 } else {
803                     holder.checkBox.setVisibility(View.GONE);
804                 }
805             }
806             mActive.remove(convertView);
807             mActive.add(convertView);
808             return convertView;
809         }
810 
811         @Override
getFilter()812         public Filter getFilter() {
813             return mFilter;
814         }
815 
816         @Override
onMovedToScrapHeap(View view)817         public void onMovedToScrapHeap(View view) {
818             mActive.remove(view);
819         }
820     }
821 
822     @Override
onCreate(Bundle savedInstanceState)823     public void onCreate(Bundle savedInstanceState) {
824         super.onCreate(savedInstanceState);
825 
826         setHasOptionsMenu(true);
827 
828         mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
829         Intent intent = getActivity().getIntent();
830         String action = intent.getAction();
831         int defaultListType = LIST_TYPE_DOWNLOADED;
832         String className = getArguments() != null
833                 ? getArguments().getString("classname") : null;
834         if (className == null) {
835             className = intent.getComponent().getClassName();
836         }
837         if (className.equals(RunningServicesActivity.class.getName())
838                 || className.endsWith(".RunningServices")) {
839             defaultListType = LIST_TYPE_RUNNING;
840         } else if (className.equals(StorageUseActivity.class.getName())
841                 || Intent.ACTION_MANAGE_PACKAGE_STORAGE.equals(action)
842                 || className.endsWith(".StorageUse")) {
843             mSortOrder = SORT_ORDER_SIZE;
844             defaultListType = LIST_TYPE_ALL;
845         } else if (Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)) {
846             // Select the all-apps list, with the default sorting
847             defaultListType = LIST_TYPE_ALL;
848         }
849 
850         if (savedInstanceState != null) {
851             mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);
852             int tmp = savedInstanceState.getInt(EXTRA_DEFAULT_LIST_TYPE, -1);
853             if (tmp != -1) defaultListType = tmp;
854             mShowBackground = savedInstanceState.getBoolean(EXTRA_SHOW_BACKGROUND, false);
855         }
856 
857         mDefaultListType = defaultListType;
858 
859         final Intent containerIntent = new Intent().setComponent(
860                 StorageMeasurement.DEFAULT_CONTAINER_COMPONENT);
861         getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);
862 
863         mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
864         mComputingSizeStr = getActivity().getText(R.string.computing_size);
865 
866         TabInfo tab = new TabInfo(this, mApplicationsState,
867                 getActivity().getString(R.string.filter_apps_third_party),
868                 LIST_TYPE_DOWNLOADED, this, savedInstanceState);
869         mTabs.add(tab);
870 
871         if (!Environment.isExternalStorageEmulated()) {
872             tab = new TabInfo(this, mApplicationsState,
873                     getActivity().getString(R.string.filter_apps_onsdcard),
874                     LIST_TYPE_SDCARD, this, savedInstanceState);
875             mTabs.add(tab);
876         }
877 
878         tab = new TabInfo(this, mApplicationsState,
879                 getActivity().getString(R.string.filter_apps_running),
880                 LIST_TYPE_RUNNING, this, savedInstanceState);
881         mTabs.add(tab);
882 
883         tab = new TabInfo(this, mApplicationsState,
884                 getActivity().getString(R.string.filter_apps_all),
885                 LIST_TYPE_ALL, this, savedInstanceState);
886         mTabs.add(tab);
887 
888         tab = new TabInfo(this, mApplicationsState,
889                 getActivity().getString(R.string.filter_apps_disabled),
890                 LIST_TYPE_DISABLED, this, savedInstanceState);
891         mTabs.add(tab);
892 
893         mNumTabs = mTabs.size();
894     }
895 
896 
897     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)898     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
899         // initialize the inflater
900         mInflater = inflater;
901 
902         View rootView = mInflater.inflate(R.layout.manage_applications_content,
903                 container, false);
904         mContentContainer = container;
905         mRootView = rootView;
906 
907         mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
908         MyPagerAdapter adapter = new MyPagerAdapter();
909         mViewPager.setAdapter(adapter);
910         mViewPager.setOnPageChangeListener(adapter);
911         PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
912         tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
913 
914         // We have to do this now because PreferenceFrameLayout looks at it
915         // only when the view is added.
916         if (container instanceof PreferenceFrameLayout) {
917             ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
918         }
919 
920         if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
921             buildResetDialog();
922         }
923 
924         if (savedInstanceState == null) {
925             // First time init: make sure view pager is showing the correct tab.
926             for (int i = 0; i < mTabs.size(); i++) {
927                 TabInfo tab = mTabs.get(i);
928                 if (tab.mListType == mDefaultListType) {
929                     mViewPager.setCurrentItem(i);
930                     break;
931                 }
932             }
933         }
934 
935         return rootView;
936     }
937 
938     @Override
onStart()939     public void onStart() {
940         super.onStart();
941     }
942 
943     @Override
onResume()944     public void onResume() {
945         super.onResume();
946         mActivityResumed = true;
947         updateNumTabs();
948         updateCurrentTab(mViewPager.getCurrentItem());
949         updateOptionsMenu();
950     }
951 
952     @Override
onSaveInstanceState(Bundle outState)953     public void onSaveInstanceState(Bundle outState) {
954         super.onSaveInstanceState(outState);
955         outState.putInt(EXTRA_SORT_ORDER, mSortOrder);
956         if (mDefaultListType != -1) {
957             outState.putInt(EXTRA_DEFAULT_LIST_TYPE, mDefaultListType);
958         }
959         outState.putBoolean(EXTRA_SHOW_BACKGROUND, mShowBackground);
960         if (mResetDialog != null) {
961             outState.putBoolean(EXTRA_RESET_DIALOG, true);
962         }
963     }
964 
965     @Override
onPause()966     public void onPause() {
967         super.onPause();
968         mActivityResumed = false;
969         for (int i=0; i<mTabs.size(); i++) {
970             mTabs.get(i).pause();
971         }
972     }
973 
974     @Override
onStop()975     public void onStop() {
976         super.onStop();
977         if (mResetDialog != null) {
978             mResetDialog.dismiss();
979             mResetDialog = null;
980         }
981     }
982 
983     @Override
onDestroyView()984     public void onDestroyView() {
985         super.onDestroyView();
986 
987         // We are going to keep the tab data structures around, but they
988         // are no longer attached to their view hierarchy.
989         for (int i=0; i<mTabs.size(); i++) {
990             mTabs.get(i).detachView();
991         }
992     }
993 
994     @Override
onActivityResult(int requestCode, int resultCode, Intent data)995     public void onActivityResult(int requestCode, int resultCode, Intent data) {
996         if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
997             mApplicationsState.requestSize(mCurrentPkgName);
998         }
999     }
1000 
updateNumTabs()1001     private void updateNumTabs() {
1002         int newNum = mApplicationsState.haveDisabledApps() ? mTabs.size() : (mTabs.size()-1);
1003         if (newNum != mNumTabs) {
1004             mNumTabs = newNum;
1005             if (mViewPager != null) {
1006                 mViewPager.getAdapter().notifyDataSetChanged();
1007             }
1008         }
1009     }
1010 
tabForType(int type)1011     TabInfo tabForType(int type) {
1012         for (int i = 0; i < mTabs.size(); i++) {
1013             TabInfo tab = mTabs.get(i);
1014             if (tab.mListType == type) {
1015                 return tab;
1016             }
1017         }
1018         return null;
1019     }
1020 
1021     // utility method used to start sub activity
startApplicationDetailsActivity()1022     private void startApplicationDetailsActivity() {
1023         // start new fragment to display extended information
1024         Bundle args = new Bundle();
1025         args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mCurrentPkgName);
1026 
1027         PreferenceActivity pa = (PreferenceActivity)getActivity();
1028         pa.startPreferencePanel(InstalledAppDetails.class.getName(), args,
1029                 R.string.application_info_label, null, this, INSTALLED_APP_DETAILS);
1030     }
1031 
1032     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)1033     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1034         mOptionsMenu = menu;
1035         // note: icons removed for now because the cause the new action
1036         // bar UI to be very confusing.
1037         menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha)
1038                 //.setIcon(android.R.drawable.ic_menu_sort_alphabetically)
1039                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1040         menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
1041                 //.setIcon(android.R.drawable.ic_menu_sort_by_size)
1042                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1043         menu.add(0, SHOW_RUNNING_SERVICES, 3, R.string.show_running_services)
1044                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
1045         menu.add(0, SHOW_BACKGROUND_PROCESSES, 3, R.string.show_background_processes)
1046                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
1047         menu.add(0, RESET_APP_PREFERENCES, 4, R.string.reset_app_preferences)
1048                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1049         updateOptionsMenu();
1050     }
1051 
1052     @Override
onPrepareOptionsMenu(Menu menu)1053     public void onPrepareOptionsMenu(Menu menu) {
1054         updateOptionsMenu();
1055     }
1056 
1057     @Override
onDestroyOptionsMenu()1058     public void onDestroyOptionsMenu() {
1059         mOptionsMenu = null;
1060     }
1061 
1062     @Override
onDestroy()1063     public void onDestroy() {
1064         getActivity().unbindService(mContainerConnection);
1065         super.onDestroy();
1066     }
1067 
updateOptionsMenu()1068     void updateOptionsMenu() {
1069         if (mOptionsMenu == null) {
1070             return;
1071         }
1072 
1073         /*
1074          * The running processes screen doesn't use the mApplicationsAdapter
1075          * so bringing up this menu in that case doesn't make any sense.
1076          */
1077         if (mCurTab != null && mCurTab.mListType == LIST_TYPE_RUNNING) {
1078             TabInfo tab = tabForType(LIST_TYPE_RUNNING);
1079             boolean showingBackground = tab != null && tab.mRunningProcessesView != null
1080                     ? tab.mRunningProcessesView.mAdapter.getShowBackground() : false;
1081             mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(false);
1082             mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(false);
1083             mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(showingBackground);
1084             mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(!showingBackground);
1085             mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(false);
1086         } else {
1087             mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
1088             mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
1089             mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(false);
1090             mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(false);
1091             mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(true);
1092         }
1093     }
1094 
buildResetDialog()1095     void buildResetDialog() {
1096         if (mResetDialog == null) {
1097             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
1098             builder.setTitle(R.string.reset_app_preferences_title);
1099             builder.setMessage(R.string.reset_app_preferences_desc);
1100             builder.setPositiveButton(R.string.reset_app_preferences_button, this);
1101             builder.setNegativeButton(R.string.cancel, null);
1102             mResetDialog = builder.show();
1103             mResetDialog.setOnDismissListener(this);
1104         }
1105     }
1106 
1107     @Override
onDismiss(DialogInterface dialog)1108     public void onDismiss(DialogInterface dialog) {
1109         if (mResetDialog == dialog) {
1110             mResetDialog = null;
1111         }
1112     }
1113 
1114 
1115     @Override
onClick(DialogInterface dialog, int which)1116     public void onClick(DialogInterface dialog, int which) {
1117         if (mResetDialog == dialog) {
1118             final PackageManager pm = getActivity().getPackageManager();
1119             final IPackageManager mIPm = IPackageManager.Stub.asInterface(
1120                     ServiceManager.getService("package"));
1121             final INotificationManager nm = INotificationManager.Stub.asInterface(
1122                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
1123             final NetworkPolicyManager npm = NetworkPolicyManager.from(getActivity());
1124             final AppOpsManager aom = (AppOpsManager)getActivity().getSystemService(
1125                     Context.APP_OPS_SERVICE);
1126             final Handler handler = new Handler(getActivity().getMainLooper());
1127             (new AsyncTask<Void, Void, Void>() {
1128                 @Override protected Void doInBackground(Void... params) {
1129                     List<ApplicationInfo> apps = pm.getInstalledApplications(
1130                             PackageManager.GET_DISABLED_COMPONENTS);
1131                     for (int i=0; i<apps.size(); i++) {
1132                         ApplicationInfo app = apps.get(i);
1133                         try {
1134                             if (DEBUG) Log.v(TAG, "Enabling notifications: " + app.packageName);
1135                             nm.setNotificationsEnabledForPackage(app.packageName, app.uid, true);
1136                         } catch (android.os.RemoteException ex) {
1137                         }
1138                         if (!app.enabled) {
1139                             if (DEBUG) Log.v(TAG, "Enabling app: " + app.packageName);
1140                             if (pm.getApplicationEnabledSetting(app.packageName)
1141                                     == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
1142                                 pm.setApplicationEnabledSetting(app.packageName,
1143                                         PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
1144                                         PackageManager.DONT_KILL_APP);
1145                             }
1146                         }
1147                     }
1148                     try {
1149                         mIPm.resetPreferredActivities(UserHandle.myUserId());
1150                     } catch (RemoteException e) {
1151                     }
1152                     aom.resetAllModes();
1153                     final int[] restrictedUids = npm.getUidsWithPolicy(
1154                             POLICY_REJECT_METERED_BACKGROUND);
1155                     final int currentUserId = ActivityManager.getCurrentUser();
1156                     for (int uid : restrictedUids) {
1157                         // Only reset for current user
1158                         if (UserHandle.getUserId(uid) == currentUserId) {
1159                             if (DEBUG) Log.v(TAG, "Clearing data policy: " + uid);
1160                             npm.setUidPolicy(uid, POLICY_NONE);
1161                         }
1162                     }
1163                     handler.post(new Runnable() {
1164                         @Override public void run() {
1165                             if (DEBUG) Log.v(TAG, "Done clearing");
1166                             if (getActivity() != null && mActivityResumed) {
1167                                 if (DEBUG) Log.v(TAG, "Updating UI!");
1168                                 for (int i=0; i<mTabs.size(); i++) {
1169                                     TabInfo tab = mTabs.get(i);
1170                                     if (tab.mApplications != null) {
1171                                         tab.mApplications.pause();
1172                                     }
1173                                 }
1174                                 if (mCurTab != null) {
1175                                     mCurTab.resume(mSortOrder);
1176                                 }
1177                             }
1178                         }
1179                     });
1180                     return null;
1181                 }
1182             }).execute();
1183         }
1184     }
1185 
1186     @Override
onOptionsItemSelected(MenuItem item)1187     public boolean onOptionsItemSelected(MenuItem item) {
1188         int menuId = item.getItemId();
1189         if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
1190             mSortOrder = menuId;
1191             if (mCurTab != null && mCurTab.mApplications != null) {
1192                 mCurTab.mApplications.rebuild(mSortOrder);
1193             }
1194         } else if (menuId == SHOW_RUNNING_SERVICES) {
1195             mShowBackground = false;
1196             if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
1197                 mCurTab.mRunningProcessesView.mAdapter.setShowBackground(false);
1198             }
1199         } else if (menuId == SHOW_BACKGROUND_PROCESSES) {
1200             mShowBackground = true;
1201             if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
1202                 mCurTab.mRunningProcessesView.mAdapter.setShowBackground(true);
1203             }
1204         } else if (menuId == RESET_APP_PREFERENCES) {
1205             buildResetDialog();
1206         } else {
1207             // Handle the home button
1208             return false;
1209         }
1210         updateOptionsMenu();
1211         return true;
1212     }
1213 
onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position, long id)1214     public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position,
1215             long id) {
1216         if (tab.mApplications != null && tab.mApplications.getCount() > position) {
1217             ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position);
1218             mCurrentPkgName = entry.info.packageName;
1219             startApplicationDetailsActivity();
1220         }
1221     }
1222 
updateCurrentTab(int position)1223     public void updateCurrentTab(int position) {
1224         TabInfo tab = mTabs.get(position);
1225         mCurTab = tab;
1226 
1227         // Put things in the correct paused/resumed state.
1228         if (mActivityResumed) {
1229             mCurTab.build(mInflater, mContentContainer, mRootView);
1230             mCurTab.resume(mSortOrder);
1231         } else {
1232             mCurTab.pause();
1233         }
1234         for (int i=0; i<mTabs.size(); i++) {
1235             TabInfo t = mTabs.get(i);
1236             if (t != mCurTab) {
1237                 t.pause();
1238             }
1239         }
1240 
1241         mCurTab.updateStorageUsage();
1242         updateOptionsMenu();
1243         final Activity host = getActivity();
1244         if (host != null) {
1245             host.invalidateOptionsMenu();
1246         }
1247     }
1248 
1249     private volatile IMediaContainerService mContainerService;
1250 
1251     private final ServiceConnection mContainerConnection = new ServiceConnection() {
1252         @Override
1253         public void onServiceConnected(ComponentName name, IBinder service) {
1254             mContainerService = IMediaContainerService.Stub.asInterface(service);
1255             for (int i=0; i<mTabs.size(); i++) {
1256                 mTabs.get(i).setContainerService(mContainerService);
1257             }
1258         }
1259 
1260         @Override
1261         public void onServiceDisconnected(ComponentName name) {
1262             mContainerService = null;
1263         }
1264     };
1265 }
1266