2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.applications;
19 import static android.net.NetworkPolicyManager.POLICY_NONE;
20 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
22 import android.app.Activity;
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.AppOpsManager;
26 import android.app.Fragment;
27 import android.app.INotificationManager;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.content.Intent;
32 import android.content.ServiceConnection;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.IPackageManager;
35 import android.content.pm.PackageInfo;
36 import android.content.pm.PackageManager;
37 import android.net.NetworkPolicyManager;
38 import android.os.AsyncTask;
39 import android.os.Bundle;
40 import android.os.Environment;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.UserHandle;
46 import android.os.UserManager;
47 import android.preference.PreferenceFrameLayout;
48 import android.provider.Settings;
49 import android.support.v4.view.PagerAdapter;
50 import android.support.v4.view.PagerTabStrip;
51 import android.support.v4.view.ViewPager;
52 import android.util.Log;
53 import android.view.LayoutInflater;
54 import android.view.Menu;
55 import android.view.MenuInflater;
56 import android.view.MenuItem;
57 import android.view.View;
58 import android.view.ViewGroup;
59 import android.view.animation.AnimationUtils;
60 import android.widget.AbsListView;
61 import android.widget.AdapterView;
62 import android.widget.AdapterView.OnItemClickListener;
63 import android.widget.AdapterView.OnItemSelectedListener;
64 import android.widget.BaseAdapter;
65 import android.widget.Filter;
66 import android.widget.Filterable;
67 import android.widget.ListView;
68 import android.widget.Spinner;
70 import com.android.internal.app.IMediaContainerService;
71 import com.android.internal.content.PackageHelper;
72 import com.android.settings.R;
73 import com.android.settings.SettingsActivity;
74 import com.android.settings.UserSpinnerAdapter;
75 import com.android.settings.Settings.RunningServicesActivity;
76 import com.android.settings.Settings.StorageUseActivity;
77 import com.android.settings.applications.ApplicationsState.AppEntry;
78 import com.android.settings.deviceinfo.StorageMeasurement;
79 import com.android.settings.Utils;
81 import java.util.ArrayList;
82 import java.util.Comparator;
83 import java.util.List;
85 final class CanBeOnSdCardChecker {
86 final IPackageManager mPm;
89 CanBeOnSdCardChecker() {
90 mPm = IPackageManager.Stub.asInterface(
91 ServiceManager.getService("package"));
96 mInstallLocation = mPm.getInstallLocation();
97 } catch (RemoteException e) {
98 Log.e("CanBeOnSdCardChecker", "Is Package Manager running?");
103 boolean check(ApplicationInfo info) {
104 boolean canBe = false;
105 if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
108 if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
109 if (info.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL ||
110 info.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
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.
126 interface AppClickListener {
127 void onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent,
128 View view, int position, long id);
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
137 public class ManageApplications extends Fragment implements
138 AppClickListener, DialogInterface.OnClickListener,
139 DialogInterface.OnDismissListener, OnItemSelectedListener {
141 static final String TAG = "ManageApplications";
142 static final boolean DEBUG = false;
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";
150 // attributes used as keys when passing values to InstalledAppDetails activity
151 public static final String APP_CHG = "chg";
153 // constant value that can be used to check return code from sub activity.
154 private static final int INSTALLED_APP_DETAILS = 1;
156 public static final int SIZE_TOTAL = 0;
157 public static final int SIZE_INTERNAL = 1;
158 public static final int SIZE_EXTERNAL = 2;
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;
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;
175 private int mSortOrder = SORT_ORDER_ALPHA;
177 private ApplicationsState mApplicationsState;
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;
190 public ApplicationsAdapter mApplications;
191 public LayoutInflater mInflater;
192 public View mRootView;
194 private IMediaContainerService mContainerService;
196 private View mLoadingContainer;
198 private View mListContainer;
200 // ListView used to display list
201 private ListView mListView;
202 // Custom view used to display running processes
203 private RunningProcessesView mRunningProcessesView;
205 //private LinearColorBar mColorBar;
206 //private TextView mStorageChartLabel;
207 //private TextView mUsedStorageText;
208 //private TextView mFreeStorageText;
209 private long mFreeStorage = 0, mAppStorage = 0, mTotalStorage = 0;
210 private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
212 final Runnable mRunningProcessesAvail = new Runnable() {
214 handleRunningProcessesAvail();
218 public TabInfo(ManageApplications owner, ApplicationsState apps,
219 CharSequence label, int listType, AppClickListener clickListener,
220 Bundle savedInstanceState) {
222 mApplicationsState = apps;
224 mListType = listType;
226 case LIST_TYPE_DOWNLOADED: mFilter = FILTER_APPS_THIRD_PARTY; break;
227 case LIST_TYPE_SDCARD: mFilter = FILTER_APPS_SDCARD; break;
228 case LIST_TYPE_DISABLED: mFilter = FILTER_APPS_DISABLED; break;
229 default: mFilter = FILTER_APPS_ALL; break;
231 mClickListener = clickListener;
232 mInvalidSizeStr = owner.getActivity().getText(R.string.invalid_size_value);
233 mComputingSizeStr = owner.getActivity().getText(R.string.computing_size);
234 mSavedInstanceState = savedInstanceState;
237 public void setContainerService(IMediaContainerService containerService) {
238 mContainerService = containerService;
239 updateStorageUsage();
242 public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
243 if (mRootView != null) {
246 mInflater = inflater;
247 mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING
248 ? R.layout.manage_applications_running
249 : R.layout.manage_applications_apps, null);
250 mLoadingContainer = mRootView.findViewById(R.id.loading_container);
251 mLoadingContainer.setVisibility(View.VISIBLE);
252 mListContainer = mRootView.findViewById(R.id.list_container);
253 if (mListContainer != null) {
254 // Create adapter and list view here
255 View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
256 ListView lv = (ListView) mListContainer.findViewById(android.R.id.list);
257 if (emptyView != null) {
258 lv.setEmptyView(emptyView);
260 lv.setOnItemClickListener(this);
261 lv.setSaveEnabled(true);
262 lv.setItemsCanFocus(true);
263 lv.setTextFilterEnabled(true);
265 mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
266 mListView.setAdapter(mApplications);
267 mListView.setRecyclerListener(mApplications);
268 //mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar);
269 //mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel);
270 //mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
271 //mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
272 Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
273 if (mFilter == FILTER_APPS_SDCARD) {
274 //mStorageChartLabel.setText(mOwner.getActivity().getText(
275 // R.string.sd_card_storage));
277 //mStorageChartLabel.setText(mOwner.getActivity().getText(
278 // R.string.internal_storage));
280 applyCurrentStorage();
282 mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
283 R.id.running_processes);
284 if (mRunningProcessesView != null) {
285 mRunningProcessesView.doCreate(mSavedInstanceState);
291 public void detachView() {
292 if (mRootView != null) {
293 ViewGroup group = (ViewGroup)mRootView.getParent();
295 group.removeView(mRootView);
300 public void resume(int sortOrder) {
301 if (mApplications != null) {
302 mApplications.resume(sortOrder);
304 if (mRunningProcessesView != null) {
305 boolean haveData = mRunningProcessesView.doResume(mOwner, mRunningProcessesAvail);
307 mRunningProcessesView.setVisibility(View.VISIBLE);
308 mLoadingContainer.setVisibility(View.INVISIBLE);
310 mLoadingContainer.setVisibility(View.VISIBLE);
315 public void pause() {
316 if (mApplications != null) {
317 mApplications.pause();
319 if (mRunningProcessesView != null) {
320 mRunningProcessesView.doPause();
324 public void release() {
325 if (mApplications != null) {
326 mApplications.release();
330 void updateStorageUsage() {
331 // Make sure a callback didn't come at an inopportune time.
332 if (mOwner.getActivity() == null) return;
333 // Doesn't make sense for stuff that is not an app list.
334 if (mApplications == null) return;
340 if (mFilter == FILTER_APPS_SDCARD) {
341 if (mContainerService != null) {
343 final long[] stats = mContainerService.getFileSystemStats(
344 Environment.getExternalStorageDirectory().getPath());
345 mTotalStorage = stats[0];
346 mFreeStorage = stats[1];
347 } catch (RemoteException e) {
348 Log.w(TAG, "Problem in container service", e);
352 if (mApplications != null) {
353 final int N = mApplications.getCount();
354 for (int i=0; i<N; i++) {
355 ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
356 mAppStorage += ae.externalCodeSize + ae.externalDataSize
357 + ae.externalCacheSize;
361 if (mContainerService != null) {
363 final long[] stats = mContainerService.getFileSystemStats(
364 Environment.getDataDirectory().getPath());
365 mTotalStorage = stats[0];
366 mFreeStorage = stats[1];
367 } catch (RemoteException e) {
368 Log.w(TAG, "Problem in container service", e);
372 final boolean emulatedStorage = Environment.isExternalStorageEmulated();
373 if (mApplications != null) {
374 final int N = mApplications.getCount();
375 for (int i=0; i<N; i++) {
376 ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
377 mAppStorage += ae.codeSize + ae.dataSize;
378 if (emulatedStorage) {
379 mAppStorage += ae.externalCodeSize + ae.externalDataSize;
383 mFreeStorage += mApplicationsState.sumCacheSizes();
386 applyCurrentStorage();
389 void applyCurrentStorage() {
390 // If view hierarchy is not yet created, no views to update.
391 if (mRootView == null) {
395 if (mTotalStorage > 0) {
396 BidiFormatter bidiFormatter = BidiFormatter.getInstance();
397 mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage,
398 mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage);
399 long usedStorage = mTotalStorage - mFreeStorage;
400 if (mLastUsedStorage != usedStorage) {
401 mLastUsedStorage = usedStorage;
402 String sizeStr = bidiFormatter.unicodeWrap(
403 Formatter.formatShortFileSize(mOwner.getActivity(), usedStorage));
404 mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
405 R.string.service_foreground_processes, sizeStr));
407 if (mLastFreeStorage != mFreeStorage) {
408 mLastFreeStorage = mFreeStorage;
409 String sizeStr = bidiFormatter.unicodeWrap(
410 Formatter.formatShortFileSize(mOwner.getActivity(), mFreeStorage));
411 mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
412 R.string.service_background_processes, sizeStr));
415 mColorBar.setRatios(0, 0, 0);
416 if (mLastUsedStorage != -1) {
417 mLastUsedStorage = -1;
418 mUsedStorageText.setText("");
420 if (mLastFreeStorage != -1) {
421 mLastFreeStorage = -1;
422 mFreeStorageText.setText("");
429 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
430 mClickListener.onItemClick(this, parent, view, position, id);
433 void handleRunningProcessesAvail() {
434 mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
435 mOwner.getActivity(), android.R.anim.fade_out));
436 mRunningProcessesView.startAnimation(AnimationUtils.loadAnimation(
437 mOwner.getActivity(), android.R.anim.fade_in));
438 mRunningProcessesView.setVisibility(View.VISIBLE);
439 mLoadingContainer.setVisibility(View.GONE);
442 private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
443 private int mNumTabs;
444 TabInfo mCurTab = null;
446 // Size resource used for packages whose size computation failed for some reason
447 CharSequence mInvalidSizeStr;
448 private CharSequence mComputingSizeStr;
450 // layout inflater object used to inflate views
451 private LayoutInflater mInflater;
453 private String mCurrentPkgName;
455 private Menu mOptionsMenu;
457 // These are for keeping track of activity and spinner switch state.
458 private boolean mActivityResumed;
460 private static final int LIST_TYPE_MISSING = -1;
461 static final int LIST_TYPE_DOWNLOADED = 0;
462 static final int LIST_TYPE_RUNNING = 1;
463 static final int LIST_TYPE_SDCARD = 2;
464 static final int LIST_TYPE_ALL = 3;
465 static final int LIST_TYPE_DISABLED = 4;
467 private boolean mShowBackground = false;
469 private int mDefaultListType = -1;
471 private ViewGroup mContentContainer;
472 private View mRootView;
473 private ViewPager mViewPager;
474 private ViewGroup mPinnedHeader;
475 private UserSpinnerAdapter mProfileSpinnerAdapter;
476 private Spinner mSpinner;
477 private Context mContext;
479 AlertDialog mResetDialog;
481 class MyPagerAdapter extends PagerAdapter
482 implements ViewPager.OnPageChangeListener {
486 public int getCount() {
491 public Object instantiateItem(ViewGroup container, int position) {
492 TabInfo tab = mTabs.get(position);
493 View root = tab.build(mInflater, mContentContainer, mRootView);
494 container.addView(root);
495 root.setTag(R.id.name, tab);
500 public void destroyItem(ViewGroup container, int position, Object object) {
501 container.removeView((View)object);
505 public boolean isViewFromObject(View view, Object object) {
506 return view == object;
510 public int getItemPosition(Object object) {
511 return super.getItemPosition(object);
512 //return ((TabInfo)((View)object).getTag(R.id.name)).mListType;
516 public CharSequence getPageTitle(int position) {
517 return mTabs.get(position).mLabel;
521 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
525 public void onPageSelected(int position) {
530 public void onPageScrollStateChanged(int state) {
531 if (state == ViewPager.SCROLL_STATE_IDLE) {
532 updateCurrentTab(mCurPos);
538 * Custom adapter implementation for the ListView
539 * This adapter maintains a map for each displayed application and its properties
540 * An index value on each AppInfo object indicates the correct position or index
541 * in the list. If the list gets updated dynamically when the user is viewing the list of
542 * applications, we need to return the correct index of position. This is done by mapping
543 * the getId methods via the package name into the internal maps and indices.
544 * The order of applications in the list is mirrored in mAppLocalList
546 static class ApplicationsAdapter extends BaseAdapter implements Filterable,
547 ApplicationsState.Callbacks, AbsListView.RecyclerListener {
548 private final ApplicationsState mState;
549 private final ApplicationsState.Session mSession;
550 private final TabInfo mTab;
551 private final Context mContext;
552 private final ArrayList<View> mActive = new ArrayList<View>();
553 private final int mFilterMode;
554 private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
555 private ArrayList<ApplicationsState.AppEntry> mEntries;
556 private boolean mResumed;
557 private int mLastSortMode=-1;
558 private boolean mWaitingForData;
559 private int mWhichSize = SIZE_TOTAL;
560 CharSequence mCurFilterPrefix;
562 private Filter mFilter = new Filter() {
564 protected FilterResults performFiltering(CharSequence constraint) {
565 ArrayList<ApplicationsState.AppEntry> entries
566 = applyPrefixFilter(constraint, mBaseEntries);
567 FilterResults fr = new FilterResults();
569 fr.count = entries.size();
574 protected void publishResults(CharSequence constraint, FilterResults results) {
575 mCurFilterPrefix = constraint;
576 mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values;
577 notifyDataSetChanged();
578 mTab.updateStorageUsage();
582 public ApplicationsAdapter(ApplicationsState state, TabInfo tab, int filterMode) {
584 mSession = state.newSession(this);
586 mContext = tab.mOwner.getActivity();
587 mFilterMode = filterMode;
590 public void resume(int sort) {
591 if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed);
595 mLastSortMode = sort;
602 public void pause() {
609 public void release() {
613 public void rebuild(int sort) {
614 if (sort == mLastSortMode) {
617 mLastSortMode = sort;
621 public void rebuild(boolean eraseold) {
622 if (DEBUG) Log.i(TAG, "Rebuilding app list...");
623 ApplicationsState.AppFilter filterObj;
624 Comparator<AppEntry> comparatorObj;
625 boolean emulated = Environment.isExternalStorageEmulated();
627 mWhichSize = SIZE_TOTAL;
629 mWhichSize = SIZE_INTERNAL;
631 switch (mFilterMode) {
632 case FILTER_APPS_THIRD_PARTY:
633 filterObj = ApplicationsState.THIRD_PARTY_FILTER;
635 case FILTER_APPS_SDCARD:
636 filterObj = ApplicationsState.ON_SD_CARD_FILTER;
638 mWhichSize = SIZE_EXTERNAL;
641 case FILTER_APPS_DISABLED:
642 filterObj = ApplicationsState.DISABLED_FILTER;
645 filterObj = ApplicationsState.ALL_ENABLED_FILTER;
648 switch (mLastSortMode) {
649 case SORT_ORDER_SIZE:
650 switch (mWhichSize) {
652 comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR;
655 comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR;
658 comparatorObj = ApplicationsState.SIZE_COMPARATOR;
663 comparatorObj = ApplicationsState.ALPHA_COMPARATOR;
666 ArrayList<ApplicationsState.AppEntry> entries
667 = mSession.rebuild(filterObj, comparatorObj);
668 if (entries == null && !eraseold) {
669 // Don't have new list yet, but can continue using the old one.
672 mBaseEntries = entries;
673 if (mBaseEntries != null) {
674 mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
678 notifyDataSetChanged();
679 mTab.updateStorageUsage();
681 if (entries == null) {
682 mWaitingForData = true;
683 mTab.mListContainer.setVisibility(View.INVISIBLE);
684 mTab.mLoadingContainer.setVisibility(View.VISIBLE);
686 mTab.mListContainer.setVisibility(View.VISIBLE);
687 mTab.mLoadingContainer.setVisibility(View.GONE);
691 ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
692 ArrayList<ApplicationsState.AppEntry> origEntries) {
693 if (prefix == null || prefix.length() == 0) {
696 String prefixStr = ApplicationsState.normalize(prefix.toString());
697 final String spacePrefixStr = " " + prefixStr;
698 ArrayList<ApplicationsState.AppEntry> newEntries
699 = new ArrayList<ApplicationsState.AppEntry>();
700 for (int i=0; i<origEntries.size(); i++) {
701 ApplicationsState.AppEntry entry = origEntries.get(i);
702 String nlabel = entry.getNormalizedLabel();
703 if (nlabel.startsWith(prefixStr) || nlabel.indexOf(spacePrefixStr) != -1) {
704 newEntries.add(entry);
712 public void onRunningStateChanged(boolean running) {
713 mTab.mOwner.getActivity().setProgressBarIndeterminateVisibility(running);
717 public void onRebuildComplete(ArrayList<AppEntry> apps) {
718 if (mTab.mLoadingContainer.getVisibility() == View.VISIBLE) {
719 mTab.mLoadingContainer.startAnimation(AnimationUtils.loadAnimation(
720 mContext, android.R.anim.fade_out));
721 mTab.mListContainer.startAnimation(AnimationUtils.loadAnimation(
722 mContext, android.R.anim.fade_in));
724 mTab.mListContainer.setVisibility(View.VISIBLE);
725 mTab.mLoadingContainer.setVisibility(View.GONE);
726 mWaitingForData = false;
728 mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
729 notifyDataSetChanged();
730 mTab.updateStorageUsage();
734 public void onPackageListChanged() {
739 public void onPackageIconChanged() {
740 // We ensure icons are loaded when their item is displayed, so
741 // don't care about icons loaded in the background.
745 public void onPackageSizeChanged(String packageName) {
746 for (int i=0; i<mActive.size(); i++) {
747 AppViewHolder holder = (AppViewHolder)mActive.get(i).getTag();
748 if (holder.entry.info.packageName.equals(packageName)) {
749 synchronized (holder.entry) {
750 holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
752 if (holder.entry.info.packageName.equals(mTab.mOwner.mCurrentPkgName)
753 && mLastSortMode == SORT_ORDER_SIZE) {
754 // We got the size information for the last app the
755 // user viewed, and are sorting by size... they may
756 // have cleared data, so we immediately want to resort
757 // the list with the new size to reflect it to the user.
760 mTab.updateStorageUsage();
767 public void onAllSizesComputed() {
768 if (mLastSortMode == SORT_ORDER_SIZE) {
771 mTab.updateStorageUsage();
774 public int getCount() {
775 return mEntries != null ? mEntries.size() : 0;
778 public Object getItem(int position) {
779 return mEntries.get(position);
782 public ApplicationsState.AppEntry getAppEntry(int position) {
783 return mEntries.get(position);
786 public long getItemId(int position) {
787 return mEntries.get(position).id;
790 public View getView(int position, View convertView, ViewGroup parent) {
791 // A ViewHolder keeps references to children views to avoid unnecessary calls
792 // to findViewById() on each row.
793 AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView);
794 convertView = holder.rootView;
796 // Bind the data efficiently with the holder
797 ApplicationsState.AppEntry entry = mEntries.get(position);
798 synchronized (entry) {
799 holder.entry = entry;
800 if (entry.label != null) {
801 holder.appName.setText(entry.label);
803 mState.ensureIcon(entry);
804 if (entry.icon != null) {
805 holder.appIcon.setImageDrawable(entry.icon);
807 holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize);
808 if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
809 holder.disabled.setVisibility(View.VISIBLE);
810 holder.disabled.setText(R.string.not_installed);
811 } else if (!entry.info.enabled) {
812 holder.disabled.setVisibility(View.VISIBLE);
813 holder.disabled.setText(R.string.disabled);
815 holder.disabled.setVisibility(View.GONE);
817 if (mFilterMode == FILTER_APPS_SDCARD) {
818 holder.checkBox.setVisibility(View.VISIBLE);
819 holder.checkBox.setChecked((entry.info.flags
820 & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
822 holder.checkBox.setVisibility(View.GONE);
825 mActive.remove(convertView);
826 mActive.add(convertView);
831 public Filter getFilter() {
836 public void onMovedToScrapHeap(View view) {
837 mActive.remove(view);
842 public void onCreate(Bundle savedInstanceState) {
843 super.onCreate(savedInstanceState);
845 setHasOptionsMenu(true);
847 mContext = getActivity();
848 mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
849 Intent intent = getActivity().getIntent();
850 String action = intent.getAction();
851 int defaultListType = LIST_TYPE_DOWNLOADED;
852 String className = getArguments() != null
853 ? getArguments().getString("classname") : null;
854 if (className == null) {
855 className = intent.getComponent().getClassName();
857 if (className.equals(RunningServicesActivity.class.getName())
858 || className.endsWith(".RunningServices")) {
859 defaultListType = LIST_TYPE_RUNNING;
860 } else if (className.equals(StorageUseActivity.class.getName())
861 || Intent.ACTION_MANAGE_PACKAGE_STORAGE.equals(action)
862 || className.endsWith(".StorageUse")) {
863 mSortOrder = SORT_ORDER_SIZE;
864 defaultListType = LIST_TYPE_ALL;
865 } else if (android.provider.Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)) {
866 // Select the all-apps list, with the default sorting
867 defaultListType = LIST_TYPE_ALL;
870 if (savedInstanceState != null) {
871 mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);
872 int tmp = savedInstanceState.getInt(EXTRA_DEFAULT_LIST_TYPE, -1);
873 if (tmp != -1) defaultListType = tmp;
874 mShowBackground = savedInstanceState.getBoolean(EXTRA_SHOW_BACKGROUND, false);
877 mDefaultListType = defaultListType;
879 final Intent containerIntent = new Intent().setComponent(
880 StorageMeasurement.DEFAULT_CONTAINER_COMPONENT);
881 getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE);
883 mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
884 mComputingSizeStr = getActivity().getText(R.string.computing_size);
886 TabInfo tab = new TabInfo(this, mApplicationsState,
887 getActivity().getString(R.string.filter_apps_third_party),
888 LIST_TYPE_DOWNLOADED, this, savedInstanceState);
891 if (!Environment.isExternalStorageEmulated()) {
892 tab = new TabInfo(this, mApplicationsState,
893 getActivity().getString(R.string.filter_apps_onsdcard),
894 LIST_TYPE_SDCARD, this, savedInstanceState);
898 tab = new TabInfo(this, mApplicationsState,
899 getActivity().getString(R.string.filter_apps_running),
900 LIST_TYPE_RUNNING, this, savedInstanceState);
903 tab = new TabInfo(this, mApplicationsState,
904 getActivity().getString(R.string.filter_apps_all),
905 LIST_TYPE_ALL, this, savedInstanceState);
908 tab = new TabInfo(this, mApplicationsState,
909 getActivity().getString(R.string.filter_apps_disabled),
910 LIST_TYPE_DISABLED, this, savedInstanceState);
913 mNumTabs = mTabs.size();
915 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
916 mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(um, mContext);
921 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
922 // initialize the inflater
923 mInflater = inflater;
925 View rootView = mInflater.inflate(R.layout.manage_applications_content,
927 mContentContainer = container;
928 mRootView = rootView;
929 mPinnedHeader = (ViewGroup) mRootView.findViewById(R.id.pinned_header);
930 if (mProfileSpinnerAdapter != null) {
931 mSpinner = (Spinner) inflater.inflate(R.layout.spinner_view, null);
932 mSpinner.setAdapter(mProfileSpinnerAdapter);
933 mSpinner.setOnItemSelectedListener(this);
934 mPinnedHeader.addView(mSpinner);
935 mPinnedHeader.setVisibility(View.VISIBLE);
937 mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
938 MyPagerAdapter adapter = new MyPagerAdapter();
939 mViewPager.setAdapter(adapter);
940 mViewPager.setOnPageChangeListener(adapter);
941 PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
942 tabs.setTabIndicatorColorResource(R.color.theme_accent);
944 // We have to do this now because PreferenceFrameLayout looks at it
945 // only when the view is added.
946 if (container instanceof PreferenceFrameLayout) {
947 ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
950 if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
954 if (savedInstanceState == null) {
955 // First time init: make sure view pager is showing the correct tab.
956 int extraCurrentListType = getActivity().getIntent().getIntExtra(EXTRA_LIST_TYPE,
958 int currentListType = (extraCurrentListType != LIST_TYPE_MISSING)
959 ? extraCurrentListType : mDefaultListType;
960 for (int i = 0; i < mNumTabs; i++) {
961 TabInfo tab = mTabs.get(i);
962 if (tab.mListType == currentListType) {
963 mViewPager.setCurrentItem(i);
973 public void onStart() {
978 public void onResume() {
980 mActivityResumed = true;
981 updateCurrentTab(mViewPager.getCurrentItem());
987 public void onSaveInstanceState(Bundle outState) {
988 super.onSaveInstanceState(outState);
989 outState.putInt(EXTRA_SORT_ORDER, mSortOrder);
990 if (mDefaultListType != -1) {
991 outState.putInt(EXTRA_DEFAULT_LIST_TYPE, mDefaultListType);
993 outState.putBoolean(EXTRA_SHOW_BACKGROUND, mShowBackground);
994 if (mResetDialog != null) {
995 outState.putBoolean(EXTRA_RESET_DIALOG, true);
1000 public void onPause() {
1002 mActivityResumed = false;
1003 for (int i=0; i<mTabs.size(); i++) {
1004 mTabs.get(i).pause();
1009 public void onStop() {
1011 if (mResetDialog != null) {
1012 mResetDialog.dismiss();
1013 mResetDialog = null;
1018 public void onDestroyView() {
1019 super.onDestroyView();
1021 // We are going to keep the tab data structures around, but they
1022 // are no longer attached to their view hierarchy.
1023 for (int i=0; i<mTabs.size(); i++) {
1024 mTabs.get(i).detachView();
1025 mTabs.get(i).release();
1030 public void onActivityResult(int requestCode, int resultCode, Intent data) {
1031 if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
1032 mApplicationsState.requestSize(mCurrentPkgName);
1037 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1038 UserHandle selectedUser = mProfileSpinnerAdapter.getUserHandle(position);
1039 if (selectedUser.getIdentifier() != UserHandle.myUserId()) {
1040 Intent intent = new Intent(Settings.ACTION_APPLICATION_SETTINGS);
1041 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1042 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
1043 int currentTab = mViewPager.getCurrentItem();
1044 intent.putExtra(EXTRA_LIST_TYPE, mTabs.get(currentTab).mListType);
1045 mContext.startActivityAsUser(intent, selectedUser);
1046 // Go back to default selection, which is the first one; this makes sure that pressing
1047 // the back button takes you into a consistent state
1048 mSpinner.setSelection(0);
1053 public void onNothingSelected(AdapterView<?> parent) {
1057 private void updateNumTabs() {
1058 int newNum = mApplicationsState.haveDisabledApps() ? mTabs.size() : (mTabs.size()-1);
1059 if (newNum != mNumTabs) {
1061 if (mViewPager != null) {
1062 mViewPager.getAdapter().notifyDataSetChanged();
1067 TabInfo tabForType(int type) {
1068 for (int i = 0; i < mTabs.size(); i++) {
1069 TabInfo tab = mTabs.get(i);
1070 if (tab.mListType == type) {
1077 // utility method used to start sub activity
1078 private void startApplicationDetailsActivity() {
1079 // start new fragment to display extended information
1080 Bundle args = new Bundle();
1081 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mCurrentPkgName);
1083 SettingsActivity sa = (SettingsActivity) getActivity();
1084 sa.startPreferencePanel(InstalledAppDetails.class.getName(), args,
1085 R.string.application_info_label, null, this, INSTALLED_APP_DETAILS);
1089 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1090 mOptionsMenu = menu;
1091 // note: icons removed for now because the cause the new action
1092 // bar UI to be very confusing.
1093 menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha)
1094 //.setIcon(android.R.drawable.ic_menu_sort_alphabetically)
1095 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1096 menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size)
1097 //.setIcon(android.R.drawable.ic_menu_sort_by_size)
1098 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1099 menu.add(0, SHOW_RUNNING_SERVICES, 3, R.string.show_running_services)
1100 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
1101 menu.add(0, SHOW_BACKGROUND_PROCESSES, 3, R.string.show_background_processes)
1102 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
1103 menu.add(0, RESET_APP_PREFERENCES, 4, R.string.reset_app_preferences)
1104 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
1105 updateOptionsMenu();
1109 public void onPrepareOptionsMenu(Menu menu) {
1110 updateOptionsMenu();
1114 public void onDestroyOptionsMenu() {
1115 mOptionsMenu = null;
1119 public void onDestroy() {
1120 getActivity().unbindService(mContainerConnection);
1124 void updateOptionsMenu() {
1125 if (mOptionsMenu == null) {
1130 * The running processes screen doesn't use the mApplicationsAdapter
1131 * so bringing up this menu in that case doesn't make any sense.
1133 if (mCurTab != null && mCurTab.mListType == LIST_TYPE_RUNNING) {
1134 TabInfo tab = tabForType(LIST_TYPE_RUNNING);
1135 boolean showingBackground = tab != null && tab.mRunningProcessesView != null
1136 ? tab.mRunningProcessesView.mAdapter.getShowBackground() : false;
1137 mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(false);
1138 mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(false);
1139 mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(showingBackground);
1140 mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(!showingBackground);
1141 mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(false);
1142 mShowBackground = showingBackground;
1144 mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA);
1145 mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE);
1146 mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(false);
1147 mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(false);
1148 mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(true);
1152 void buildResetDialog() {
1153 if (mResetDialog == null) {
1154 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
1155 builder.setTitle(R.string.reset_app_preferences_title);
1156 builder.setMessage(R.string.reset_app_preferences_desc);
1157 builder.setPositiveButton(R.string.reset_app_preferences_button, this);
1158 builder.setNegativeButton(R.string.cancel, null);
1159 mResetDialog = builder.show();
1160 mResetDialog.setOnDismissListener(this);
1165 public void onDismiss(DialogInterface dialog) {
1166 if (mResetDialog == dialog) {
1167 mResetDialog = null;
1173 public void onClick(DialogInterface dialog, int which) {
1174 if (mResetDialog == dialog) {
1175 final PackageManager pm = getActivity().getPackageManager();
1176 final IPackageManager mIPm = IPackageManager.Stub.asInterface(
1177 ServiceManager.getService("package"));
1178 final INotificationManager nm = INotificationManager.Stub.asInterface(
1179 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
1180 final NetworkPolicyManager npm = NetworkPolicyManager.from(getActivity());
1181 final AppOpsManager aom = (AppOpsManager)getActivity().getSystemService(
1182 Context.APP_OPS_SERVICE);
1183 final Handler handler = new Handler(getActivity().getMainLooper());
1184 (new AsyncTask<Void, Void, Void>() {
1185 @Override protected Void doInBackground(Void... params) {
1186 List<ApplicationInfo> apps = pm.getInstalledApplications(
1187 PackageManager.GET_DISABLED_COMPONENTS);
1188 for (int i=0; i<apps.size(); i++) {
1189 ApplicationInfo app = apps.get(i);
1191 if (DEBUG) Log.v(TAG, "Enabling notifications: " + app.packageName);
1192 nm.setNotificationsEnabledForPackage(app.packageName, app.uid, true);
1193 } catch (android.os.RemoteException ex) {
1196 if (DEBUG) Log.v(TAG, "Enabling app: " + app.packageName);
1197 if (pm.getApplicationEnabledSetting(app.packageName)
1198 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
1199 pm.setApplicationEnabledSetting(app.packageName,
1200 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
1201 PackageManager.DONT_KILL_APP);
1206 mIPm.resetPreferredActivities(UserHandle.myUserId());
1207 } catch (RemoteException e) {
1209 aom.resetAllModes();
1210 final int[] restrictedUids = npm.getUidsWithPolicy(
1211 POLICY_REJECT_METERED_BACKGROUND);
1212 final int currentUserId = ActivityManager.getCurrentUser();
1213 for (int uid : restrictedUids) {
1214 // Only reset for current user
1215 if (UserHandle.getUserId(uid) == currentUserId) {
1216 if (DEBUG) Log.v(TAG, "Clearing data policy: " + uid);
1217 npm.setUidPolicy(uid, POLICY_NONE);
1220 handler.post(new Runnable() {
1221 @Override public void run() {
1222 if (DEBUG) Log.v(TAG, "Done clearing");
1223 if (getActivity() != null && mActivityResumed) {
1224 if (DEBUG) Log.v(TAG, "Updating UI!");
1225 for (int i=0; i<mTabs.size(); i++) {
1226 TabInfo tab = mTabs.get(i);
1227 if (tab.mApplications != null) {
1228 tab.mApplications.pause();
1231 if (mCurTab != null) {
1232 mCurTab.resume(mSortOrder);
1244 public boolean onOptionsItemSelected(MenuItem item) {
1245 int menuId = item.getItemId();
1246 if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) {
1247 mSortOrder = menuId;
1248 if (mCurTab != null && mCurTab.mApplications != null) {
1249 mCurTab.mApplications.rebuild(mSortOrder);
1251 } else if (menuId == SHOW_RUNNING_SERVICES) {
1252 mShowBackground = false;
1253 if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
1254 mCurTab.mRunningProcessesView.mAdapter.setShowBackground(false);
1256 } else if (menuId == SHOW_BACKGROUND_PROCESSES) {
1257 mShowBackground = true;
1258 if (mCurTab != null && mCurTab.mRunningProcessesView != null) {
1259 mCurTab.mRunningProcessesView.mAdapter.setShowBackground(true);
1261 } else if (menuId == RESET_APP_PREFERENCES) {
1264 // Handle the home button
1267 updateOptionsMenu();
1271 public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position,
1273 if (tab.mApplications != null && tab.mApplications.getCount() > position) {
1274 ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position);
1275 mCurrentPkgName = entry.info.packageName;
1276 startApplicationDetailsActivity();
1280 public void updateCurrentTab(int position) {
1281 TabInfo tab = mTabs.get(position);
1284 // Put things in the correct paused/resumed state.
1285 if (mActivityResumed) {
1286 mCurTab.build(mInflater, mContentContainer, mRootView);
1287 mCurTab.resume(mSortOrder);
1291 for (int i=0; i<mTabs.size(); i++) {
1292 TabInfo t = mTabs.get(i);
1298 mCurTab.updateStorageUsage();
1299 updateOptionsMenu();
1300 final Activity host = getActivity();
1302 host.invalidateOptionsMenu();
1306 private volatile IMediaContainerService mContainerService;
1308 private final ServiceConnection mContainerConnection = new ServiceConnection() {
1310 public void onServiceConnected(ComponentName name, IBinder service) {
1311 mContainerService = IMediaContainerService.Stub.asInterface(service);
1312 for (int i=0; i<mTabs.size(); i++) {
1313 mTabs.get(i).setContainerService(mContainerService);
1318 public void onServiceDisconnected(ComponentName name) {
1319 mContainerService = null;