From 4bb075bc4fb415eacb0fe2d7e74f16de2d9c718a Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 17 Mar 2015 10:06:58 -0400 Subject: Add data item to app info screen Add link from app info to directly viewing data usage for that app. Also do some minor tweaks to get ordering and summaries right on the app info screen. Bug: 19511439 Change-Id: Ic50dc24bf9a5c1fe6a7aa076772915ba61168fac --- src/com/android/settings/DataUsageSummary.java | 54 ++++++++++++- .../settings/applications/InstalledAppDetails.java | 93 +++++++++++++++++++++- 2 files changed, 141 insertions(+), 6 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java index cba0879..3ab1d23 100644 --- a/src/com/android/settings/DataUsageSummary.java +++ b/src/com/android/settings/DataUsageSummary.java @@ -62,6 +62,7 @@ import android.content.Intent; import android.content.Loader; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; @@ -120,6 +121,7 @@ import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.Switch; import android.widget.TabHost; +import android.widget.Toast; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabContentFactory; import android.widget.TabHost.TabSpec; @@ -142,7 +144,6 @@ import com.android.settings.sim.SimSettings; import com.android.settings.widget.ChartDataUsageView; import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener; import com.android.settings.widget.ChartNetworkSeriesView; - import com.google.android.collect.Lists; import libcore.util.Objects; @@ -191,6 +192,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable "data_usage_disable_mobile_limit"; private static final String DATA_USAGE_CYCLE_KEY = "data_usage_cycle"; + public static final String EXTRA_SHOW_APP_IMMEDIATE_PKG = "showAppImmediatePkg"; + private static final int LOADER_CHART_DATA = 2; private static final int LOADER_SUMMARY = 3; @@ -281,6 +284,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private UidDetailProvider mUidDetailProvider; + // Indicates request to show app immediately rather than list. + private String mShowAppImmediatePkg; + /** * Local cache of data enabled for subId, used to work around delays. */ @@ -332,6 +338,13 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mShowEthernet = true; } + mUidDetailProvider = new UidDetailProvider(context); + + Bundle arguments = getArguments(); + if (arguments != null) { + mShowAppImmediatePkg = arguments.getString(EXTRA_SHOW_APP_IMMEDIATE_PKG); + } + setHasOptionsMenu(true); } @@ -342,7 +355,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable final Context context = inflater.getContext(); final View view = inflater.inflate(R.layout.data_usage_summary, container, false); - mUidDetailProvider = new UidDetailProvider(context); mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container); @@ -448,9 +460,34 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable mListView.setOnItemClickListener(mListListener); mListView.setAdapter(mAdapter); + showRequestedAppIfNeeded(); + return view; } + private void showRequestedAppIfNeeded() { + if (mShowAppImmediatePkg == null) { + return; + } + try { + int uid = getActivity().getPackageManager().getPackageUid(mShowAppImmediatePkg, + UserHandle.myUserId()); + AppItem app = new AppItem(uid); + app.addUid(uid); + + final UidDetail detail = mUidDetailProvider.getUidDetail(app.key, true); + // When we are going straight to an app then we are coming from App Info and want + // a header at the top. + AppHeader.createAppHeader(getActivity(), detail.icon, detail.label, null); + AppDetailsFragment.show(DataUsageSummary.this, app, detail.label, false); + } catch (NameNotFoundException e) { + Log.w(TAG, "Could not find " + mShowAppImmediatePkg, e); + Toast.makeText(getActivity(), getString(R.string.unknown_app), Toast.LENGTH_LONG) + .show(); + getActivity().finish(); + } + } + @Override public void onViewStateRestored(Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); @@ -639,6 +676,10 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable * only be assigned after initial layout is complete. */ private void ensureLayoutTransitions() { + if (mShowAppImmediatePkg != null) { + // If we are skipping right to showing an app, we don't care about transitions. + return; + } // skip when already setup if (mChart.getLayoutTransition() != null) return; @@ -1887,6 +1928,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable private static final String EXTRA_APP = "app"; public static void show(DataUsageSummary parent, AppItem app, CharSequence label) { + show(parent, app, label, true); + } + + public static void show(DataUsageSummary parent, AppItem app, CharSequence label, + boolean addToBack) { if (!parent.isAdded()) return; final Bundle args = new Bundle(); @@ -1897,7 +1943,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable fragment.setTargetFragment(parent, 0); final FragmentTransaction ft = parent.getFragmentManager().beginTransaction(); ft.add(fragment, TAG_APP_DETAILS); - ft.addToBackStack(TAG_APP_DETAILS); + if (addToBack) { + ft.addToBackStack(TAG_APP_DETAILS); + } ft.setBreadCrumbTitle( parent.getResources().getString(R.string.data_usage_app_summary_title)); ft.commitAllowingStateLoss(); diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index 59dbd0e..7f20b32 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -19,23 +19,33 @@ package com.android.settings.applications; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; +import android.app.LoaderManager.LoaderCallbacks; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.Loader; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; +import android.net.NetworkTemplate; +import android.net.TrafficStats; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.provider.Settings; +import android.text.format.DateUtils; +import android.text.format.Formatter; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -44,10 +54,14 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import com.android.settings.DataUsageSummary; +import com.android.settings.DataUsageSummary.AppItem; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; +import com.android.settings.net.ChartData; +import com.android.settings.net.ChartDataLoader; import com.android.settings.notification.NotificationAppList; import com.android.settings.notification.NotificationAppList.AppRow; import com.android.settings.notification.NotificationAppList.Backend; @@ -76,6 +90,8 @@ public class InstalledAppDetails extends AppInfoBase public static final int REQUEST_UNINSTALL = 0; private static final int SUB_INFO_FRAGMENT = 1; + private static final int LOADER_CHART_DATA = 2; + private static final int DLG_FORCE_STOP = DLG_BASE + 1; private static final int DLG_DISABLE = DLG_BASE + 2; private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; @@ -109,6 +125,9 @@ public class InstalledAppDetails extends AppInfoBase // Used for updating notification preference. private final Backend mBackend = new Backend(); + private ChartData mChartData; + private INetworkStatsSession mStatsSession; + private boolean handleDisableable(Button button) { boolean disableable = false; // Try to prevent the user from bricking their phone @@ -207,6 +226,37 @@ public class InstalledAppDetails extends AppInfoBase setHasOptionsMenu(true); addPreferencesFromResource(R.xml.installed_app_details); + + INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + try { + mStatsSession = statsService.openSession(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onResume() { + super.onResume(); + AppItem app = new AppItem(mAppEntry.info.uid); + app.addUid(mAppEntry.info.uid); + getLoaderManager().restartLoader(LOADER_CHART_DATA, + ChartDataLoader.buildArgs(NetworkTemplate.buildTemplateMobileWildcard(), app), + mDataCallbacks); + } + + @Override + public void onPause() { + getLoaderManager().destroyLoader(LOADER_CHART_DATA); + super.onPause(); + } + + @Override + public void onDestroy() { + TrafficStats.closeQuietly(mStatsSession); + + super.onDestroy(); } public void onActivityCreated(Bundle savedInstanceState) { @@ -223,8 +273,6 @@ public class InstalledAppDetails extends AppInfoBase mLaunchPreference.setOnPreferenceClickListener(this); mDataPreference = findPreference(KEY_DATA); mDataPreference.setOnPreferenceClickListener(this); - // Data isn't ready, lets just pull it for now. - getPreferenceScreen().removePreference(mDataPreference); } private void handleHeader() { @@ -384,6 +432,7 @@ public class InstalledAppDetails extends AppInfoBase mPm, context)); mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context, mBackend)); + mDataPreference.setSummary(getDataSummary()); if (!mInitialized) { // First time init: are we displaying an uninstalled app? @@ -410,6 +459,18 @@ public class InstalledAppDetails extends AppInfoBase return true; } + private CharSequence getDataSummary() { + if (mChartData != null) { + long totalBytes = mChartData.detail.getTotalBytes(); + Context context = getActivity(); + return getString(R.string.data_summary_format, + Formatter.formatFileSize(context, totalBytes), + DateUtils.formatDateTime(context, mChartData.detail.getStart(), + DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH)); + } + return getString(R.string.computing_size); + } + @Override protected AlertDialog createDialog(int id, int errorCode) { switch (id) { @@ -579,7 +640,13 @@ public class InstalledAppDetails extends AppInfoBase } else if (preference == mLaunchPreference) { startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle()); } else if (preference == mDataPreference) { - // Not yet. + Bundle args = new Bundle(); + args.putString(DataUsageSummary.EXTRA_SHOW_APP_IMMEDIATE_PKG, + mAppEntry.info.packageName); + + SettingsActivity sa = (SettingsActivity) getActivity(); + sa.startPreferencePanel(DataUsageSummary.class.getName(), args, -1, + getString(R.string.app_data_usage), this, SUB_INFO_FRAGMENT); } else { return false; } @@ -627,6 +694,26 @@ public class InstalledAppDetails extends AppInfoBase } } + private final LoaderCallbacks mDataCallbacks = new LoaderCallbacks() { + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new ChartDataLoader(getActivity(), mStatsSession, args); + } + + @Override + public void onLoadFinished(Loader loader, ChartData data) { + mChartData = data; + mDataPreference.setSummary(getDataSummary()); + } + + @Override + public void onLoaderReset(Loader loader) { + mChartData = null; + mDataPreference.setSummary(getDataSummary()); + } + }; + private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { -- cgit v1.1