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