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