Merge "Add data item to app info screen"

This commit is contained in:
Jason Monk
2015-03-18 14:44:43 +00:00
committed by Android (Google) Code Review
5 changed files with 166 additions and 22 deletions

View File

@@ -36,7 +36,7 @@
android:layout_alignWithParentIfMissing="true" android:layout_alignWithParentIfMissing="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:textAppearance="@style/TextAppearance.Switch" android:textAppearance="@style/TextAppearance.Switch"
android:textColor="?android:attr/textColorPrimary" android:textColor="@android:color/white"
android:textAlignment="viewStart" /> android:textAlignment="viewStart" />
<ImageView <ImageView

View File

@@ -6040,11 +6040,17 @@
<string name="launch_by_default">Launch by default</string> <string name="launch_by_default">Launch by default</string>
<!-- Summary for app storage preference [CHAR LIMIT=15] --> <!-- 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> <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>
<!-- Internal storage label [CHAR LIMIT=25] -->
<string name="storage_type_internal">internal memory</string> <!-- Summary describing internal storage for applications [CHAR LIMIT=25] -->
<!-- External storage label [CHAR LIMIT=25] --> <string name="storage_type_internal">internal storage</string>
<string name="storage_type_external">external memory</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] --> <!-- App notification summary with notifications enabled [CHAR LIMIT=40] -->
<string name="notifications_enabled">On</string> <string name="notifications_enabled">On</string>
@@ -6068,4 +6074,7 @@
<!-- Launch defaults preference summary with none set [CHAR LIMIT=40] --> <!-- Launch defaults preference summary with none set [CHAR LIMIT=40] -->
<string name="launch_defaults_none">No defaults set</string> <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> </resources>

View File

@@ -20,26 +20,26 @@
android:key="header_view" android:key="header_view"
android:layout="@layout/installed_app_details" /> android:layout="@layout/installed_app_details" />
<Preference
android:key="notification_settings"
android:title="@string/notification_section_header"
android:selectable="true" />
<Preference <Preference
android:key="storage_settings" android:key="storage_settings"
android:title="@string/storage_settings" android:title="@string/storage_settings"
android:selectable="true" /> android:selectable="true" />
<Preference
android:key="permission_settings"
android:title="@string/permissions_label"
android:selectable="true" />
<Preference <Preference
android:key="data_settings" android:key="data_settings"
android:title="@string/data_size_label" android:title="@string/data_size_label"
android:selectable="true" /> android:selectable="true" />
<Preference
android:key="permission_settings"
android:title="@string/permissions_label"
android:selectable="true" />
<Preference
android:key="notification_settings"
android:title="@string/notification_section_header"
android:selectable="true" />
<Preference <Preference
android:key="preferred_settings" android:key="preferred_settings"
android:title="@string/launch_by_default" android:title="@string/launch_by_default"

View File

@@ -62,6 +62,7 @@ import android.content.Intent;
import android.content.Loader; import android.content.Loader;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
@@ -120,6 +121,7 @@ import android.widget.ProgressBar;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TabHost; import android.widget.TabHost;
import android.widget.Toast;
import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabContentFactory; import android.widget.TabHost.TabContentFactory;
import android.widget.TabHost.TabSpec; 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;
import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener; import com.android.settings.widget.ChartDataUsageView.DataUsageChartListener;
import com.android.settings.widget.ChartNetworkSeriesView; import com.android.settings.widget.ChartNetworkSeriesView;
import com.google.android.collect.Lists; import com.google.android.collect.Lists;
import libcore.util.Objects; import libcore.util.Objects;
@@ -191,6 +192,8 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
"data_usage_disable_mobile_limit"; "data_usage_disable_mobile_limit";
private static final String DATA_USAGE_CYCLE_KEY = "data_usage_cycle"; 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_CHART_DATA = 2;
private static final int LOADER_SUMMARY = 3; private static final int LOADER_SUMMARY = 3;
@@ -281,6 +284,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
private UidDetailProvider mUidDetailProvider; 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. * 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; mShowEthernet = true;
} }
mUidDetailProvider = new UidDetailProvider(context);
Bundle arguments = getArguments();
if (arguments != null) {
mShowAppImmediatePkg = arguments.getString(EXTRA_SHOW_APP_IMMEDIATE_PKG);
}
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@@ -342,7 +355,6 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
final Context context = inflater.getContext(); final Context context = inflater.getContext();
final View view = inflater.inflate(R.layout.data_usage_summary, container, false); final View view = inflater.inflate(R.layout.data_usage_summary, container, false);
mUidDetailProvider = new UidDetailProvider(context);
mTabHost = (TabHost) view.findViewById(android.R.id.tabhost); mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container); mTabsContainer = (ViewGroup) view.findViewById(R.id.tabs_container);
@@ -448,9 +460,34 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
mListView.setOnItemClickListener(mListListener); mListView.setOnItemClickListener(mListListener);
mListView.setAdapter(mAdapter); mListView.setAdapter(mAdapter);
showRequestedAppIfNeeded();
return view; 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 @Override
public void onViewStateRestored(Bundle savedInstanceState) { public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState); super.onViewStateRestored(savedInstanceState);
@@ -639,6 +676,10 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
* only be assigned after initial layout is complete. * only be assigned after initial layout is complete.
*/ */
private void ensureLayoutTransitions() { 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 // skip when already setup
if (mChart.getLayoutTransition() != null) return; if (mChart.getLayoutTransition() != null) return;
@@ -1887,6 +1928,11 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
private static final String EXTRA_APP = "app"; private static final String EXTRA_APP = "app";
public static void show(DataUsageSummary parent, AppItem app, CharSequence label) { 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; if (!parent.isAdded()) return;
final Bundle args = new Bundle(); final Bundle args = new Bundle();
@@ -1897,7 +1943,9 @@ public class DataUsageSummary extends HighlightingFragment implements Indexable
fragment.setTargetFragment(parent, 0); fragment.setTargetFragment(parent, 0);
final FragmentTransaction ft = parent.getFragmentManager().beginTransaction(); final FragmentTransaction ft = parent.getFragmentManager().beginTransaction();
ft.add(fragment, TAG_APP_DETAILS); ft.add(fragment, TAG_APP_DETAILS);
ft.addToBackStack(TAG_APP_DETAILS); if (addToBack) {
ft.addToBackStack(TAG_APP_DETAILS);
}
ft.setBreadCrumbTitle( ft.setBreadCrumbTitle(
parent.getResources().getString(R.string.data_usage_app_summary_title)); parent.getResources().getString(R.string.data_usage_app_summary_title));
ft.commitAllowingStateLoss(); ft.commitAllowingStateLoss();

View File

@@ -19,23 +19,33 @@ package com.android.settings.applications;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.Loader;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo; 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.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.provider.Settings; import android.provider.Settings;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@@ -44,10 +54,14 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.android.settings.DataUsageSummary;
import com.android.settings.DataUsageSummary.AppItem;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry; 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;
import com.android.settings.notification.NotificationAppList.AppRow; import com.android.settings.notification.NotificationAppList.AppRow;
import com.android.settings.notification.NotificationAppList.Backend; import com.android.settings.notification.NotificationAppList.Backend;
@@ -76,6 +90,8 @@ public class InstalledAppDetails extends AppInfoBase
public static final int REQUEST_UNINSTALL = 0; public static final int REQUEST_UNINSTALL = 0;
private static final int SUB_INFO_FRAGMENT = 1; 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_FORCE_STOP = DLG_BASE + 1;
private static final int DLG_DISABLE = DLG_BASE + 2; private static final int DLG_DISABLE = DLG_BASE + 2;
private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
@@ -109,6 +125,9 @@ public class InstalledAppDetails extends AppInfoBase
// Used for updating notification preference. // Used for updating notification preference.
private final Backend mBackend = new Backend(); private final Backend mBackend = new Backend();
private ChartData mChartData;
private INetworkStatsSession mStatsSession;
private boolean handleDisableable(Button button) { private boolean handleDisableable(Button button) {
boolean disableable = false; boolean disableable = false;
// Try to prevent the user from bricking their phone // Try to prevent the user from bricking their phone
@@ -207,6 +226,37 @@ public class InstalledAppDetails extends AppInfoBase
setHasOptionsMenu(true); setHasOptionsMenu(true);
addPreferencesFromResource(R.xml.installed_app_details); 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) { public void onActivityCreated(Bundle savedInstanceState) {
@@ -223,8 +273,6 @@ public class InstalledAppDetails extends AppInfoBase
mLaunchPreference.setOnPreferenceClickListener(this); mLaunchPreference.setOnPreferenceClickListener(this);
mDataPreference = findPreference(KEY_DATA); mDataPreference = findPreference(KEY_DATA);
mDataPreference.setOnPreferenceClickListener(this); mDataPreference.setOnPreferenceClickListener(this);
// Data isn't ready, lets just pull it for now.
getPreferenceScreen().removePreference(mDataPreference);
} }
private void handleHeader() { private void handleHeader() {
@@ -384,6 +432,7 @@ public class InstalledAppDetails extends AppInfoBase
mPm, context)); mPm, context));
mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context, mNotificationPreference.setSummary(getNotificationSummary(mAppEntry, context,
mBackend)); mBackend));
mDataPreference.setSummary(getDataSummary());
if (!mInitialized) { if (!mInitialized) {
// First time init: are we displaying an uninstalled app? // First time init: are we displaying an uninstalled app?
@@ -410,6 +459,18 @@ public class InstalledAppDetails extends AppInfoBase
return true; 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 @Override
protected AlertDialog createDialog(int id, int errorCode) { protected AlertDialog createDialog(int id, int errorCode) {
switch (id) { switch (id) {
@@ -579,7 +640,13 @@ public class InstalledAppDetails extends AppInfoBase
} else if (preference == mLaunchPreference) { } else if (preference == mLaunchPreference) {
startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle()); startAppInfoFragment(AppLaunchSettings.class, mLaunchPreference.getTitle());
} else if (preference == mDataPreference) { } 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 { } else {
return false; 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() { private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {