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