summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/app_header.xml2
-rw-r--r--res/values/strings.xml19
-rw-r--r--res/xml/installed_app_details.xml12
-rw-r--r--src/com/android/settings/DataUsageSummary.java54
-rwxr-xr-xsrc/com/android/settings/applications/InstalledAppDetails.java93
5 files changed, 162 insertions, 18 deletions
diff --git a/res/layout/app_header.xml b/res/layout/app_header.xml
index 8c3ca4b..d9453f4 100644
--- a/res/layout/app_header.xml
+++ b/res/layout/app_header.xml
@@ -36,7 +36,7 @@
android:layout_alignWithParentIfMissing="true"
android:layout_centerVertical="true"
android:textAppearance="@style/TextAppearance.Switch"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="@android:color/white"
android:textAlignment="viewStart" />
<ImageView
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 441034c..f2edaca 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6040,11 +6040,17 @@
<string name="launch_by_default">Launch by default</string>
<!-- Summary for app storage preference [CHAR LIMIT=15] -->
- <string name="storage_summary_format"><xliff:g id="size" example="30.00MB">%1$s</xliff:g> used in <xliff:g id="storage_type" example="internal memory">%2$s</xliff:g></string>
- <!-- Internal storage label [CHAR LIMIT=25] -->
- <string name="storage_type_internal">internal memory</string>
- <!-- External storage label [CHAR LIMIT=25] -->
- <string name="storage_type_external">external memory</string>
+ <string name="storage_summary_format"><xliff:g id="size" example="30.00MB">%1$s</xliff:g> used in <xliff:g id="storage_type" example="internal storage">%2$s</xliff:g></string>
+
+ <!-- Summary describing internal storage for applications [CHAR LIMIT=25] -->
+ <string name="storage_type_internal">internal storage</string>
+ <!-- Summary describing external storage for applications [CHAR LIMIT=25] -->
+ <string name="storage_type_external">external storage</string>
+
+ <!-- Title for data usage screen when entered from app info [CHAR LIMIT=30] -->
+ <string name="app_data_usage">App data usage</string>
+ <!-- Summary for data usage preference [CHAR LIMIT=15] -->
+ <string name="data_summary_format"><xliff:g id="size" example="30.00MB">%1$s</xliff:g> used since <xliff:g id="date" example="Jan 12">%2$s</xliff:g></string>
<!-- App notification summary with notifications enabled [CHAR LIMIT=40] -->
<string name="notifications_enabled">On</string>
@@ -6068,4 +6074,7 @@
<!-- Launch defaults preference summary with none set [CHAR LIMIT=40] -->
<string name="launch_defaults_none">No defaults set</string>
+ <!-- Warning toast shown when data usage screen can't find specified app -->
+ <string name="unknown_app">Unknown app</string>
+
</resources>
diff --git a/res/xml/installed_app_details.xml b/res/xml/installed_app_details.xml
index 05bea5c..2f72f5d 100644
--- a/res/xml/installed_app_details.xml
+++ b/res/xml/installed_app_details.xml
@@ -21,13 +21,13 @@
android:layout="@layout/installed_app_details" />
<Preference
- android:key="notification_settings"
- android:title="@string/notification_section_header"
+ android:key="storage_settings"
+ android:title="@string/storage_settings"
android:selectable="true" />
<Preference
- android:key="storage_settings"
- android:title="@string/storage_settings"
+ android:key="data_settings"
+ android:title="@string/data_size_label"
android:selectable="true" />
<Preference
@@ -36,8 +36,8 @@
android:selectable="true" />
<Preference
- android:key="data_settings"
- android:title="@string/data_size_label"
+ android:key="notification_settings"
+ android:title="@string/notification_section_header"
android:selectable="true" />
<Preference
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<ChartData> mDataCallbacks = new LoaderCallbacks<ChartData>() {
+
+ @Override
+ public Loader<ChartData> onCreateLoader(int id, Bundle args) {
+ return new ChartDataLoader(getActivity(), mStatsSession, args);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
+ mChartData = data;
+ mDataPreference.setSummary(getDataSummary());
+ }
+
+ @Override
+ public void onLoaderReset(Loader<ChartData> loader) {
+ mChartData = null;
+ mDataPreference.setSummary(getDataSummary());
+ }
+ };
+
private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {