2 * Copyright (C) 2016 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
15 package com.android.settings.datausage;
17 import android.app.LoaderManager;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.Loader;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.UserInfo;
24 import android.graphics.drawable.Drawable;
25 import android.net.INetworkStatsSession;
26 import android.net.NetworkPolicy;
27 import android.net.NetworkStatsHistory;
28 import android.net.NetworkTemplate;
29 import android.net.TrafficStats;
30 import android.os.AsyncTask;
31 import android.os.Bundle;
32 import android.os.Process;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.os.UserManager;
36 import android.support.v14.preference.SwitchPreference;
37 import android.support.v7.preference.Preference;
38 import android.support.v7.preference.PreferenceCategory;
39 import android.text.format.Formatter;
40 import android.util.ArraySet;
41 import android.view.View;
42 import android.widget.AdapterView;
43 import com.android.internal.logging.MetricsProto.MetricsEvent;
44 import com.android.settings.AppHeader;
45 import com.android.settings.R;
46 import com.android.settings.applications.AppInfoBase;
47 import com.android.settingslib.AppItem;
48 import com.android.settingslib.Utils;
49 import com.android.settingslib.net.ChartData;
50 import com.android.settingslib.net.ChartDataLoader;
51 import com.android.settingslib.net.UidDetailProvider;
53 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
55 public class AppDataUsage extends DataUsageBase implements Preference.OnPreferenceChangeListener,
56 DataSaverBackend.Listener {
58 public static final String ARG_APP_ITEM = "app_item";
59 public static final String ARG_NETWORK_TEMPLATE = "network_template";
61 private static final String KEY_TOTAL_USAGE = "total_usage";
62 private static final String KEY_FOREGROUND_USAGE = "foreground_usage";
63 private static final String KEY_BACKGROUND_USAGE = "background_usage";
64 private static final String KEY_APP_SETTINGS = "app_settings";
65 private static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
66 private static final String KEY_APP_LIST = "app_list";
67 private static final String KEY_CYCLE = "cycle";
68 private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
70 private static final int LOADER_CHART_DATA = 2;
72 private final ArraySet<String> mPackages = new ArraySet<>();
73 private Preference mTotalUsage;
74 private Preference mForegroundUsage;
75 private Preference mBackgroundUsage;
76 private Preference mAppSettings;
77 private SwitchPreference mRestrictBackground;
78 private PreferenceCategory mAppList;
80 private Drawable mIcon;
81 private CharSequence mLabel;
82 private String mPackageName;
83 private INetworkStatsSession mStatsSession;
84 private CycleAdapter mCycleAdapter;
88 private ChartData mChartData;
89 private NetworkTemplate mTemplate;
90 private NetworkPolicy mPolicy;
91 private AppItem mAppItem;
92 private Intent mAppSettingsIntent;
93 private SpinnerPreference mCycle;
94 private SwitchPreference mUnrestrictedData;
95 private DataSaverBackend mDataSaverBackend;
98 public void onCreate(Bundle icicle) {
99 super.onCreate(icicle);
100 final Bundle args = getArguments();
103 mStatsSession = services.mStatsService.openSession();
104 } catch (RemoteException e) {
105 throw new RuntimeException(e);
108 mAppItem = (args != null) ? (AppItem) args.getParcelable(ARG_APP_ITEM) : null;
109 mTemplate = (args != null) ? (NetworkTemplate) args.getParcelable(ARG_NETWORK_TEMPLATE)
111 if (mTemplate == null) {
112 Context context = getContext();
113 mTemplate = DataUsageSummary.getDefaultTemplate(context,
114 DataUsageSummary.getDefaultSubscriptionId(context));
116 if (mAppItem == null) {
117 int uid = (args != null) ? args.getInt(AppInfoBase.ARG_PACKAGE_UID, -1)
118 : getActivity().getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
121 getActivity().finish();
124 mAppItem = new AppItem(uid);
125 mAppItem.addUid(uid);
128 for (int i = 0; i < mAppItem.uids.size(); i++) {
129 addUid(mAppItem.uids.keyAt(i));
132 addPreferencesFromResource(R.xml.app_data_usage);
134 mTotalUsage = findPreference(KEY_TOTAL_USAGE);
135 mForegroundUsage = findPreference(KEY_FOREGROUND_USAGE);
136 mBackgroundUsage = findPreference(KEY_BACKGROUND_USAGE);
138 mCycle = (SpinnerPreference) findPreference(KEY_CYCLE);
139 mCycleAdapter = new CycleAdapter(getContext(), mCycle, mCycleListener, false);
141 if (UserHandle.isApp(mAppItem.key) || mAppItem.key == Process.SYSTEM_UID) {
142 if (mPackages.size() != 0) {
143 PackageManager pm = getPackageManager();
145 ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
146 mIcon = info.loadIcon(pm);
147 mLabel = info.loadLabel(pm);
148 mPackageName = info.packageName;
149 } catch (PackageManager.NameNotFoundException e) {
152 if (mAppItem.key == Process.SYSTEM_UID) {
153 removePreference(KEY_UNRESTRICTED_DATA);
154 removePreference(KEY_RESTRICT_BACKGROUND);
156 mRestrictBackground = (SwitchPreference) findPreference(KEY_RESTRICT_BACKGROUND);
157 mRestrictBackground.setOnPreferenceChangeListener(this);
158 mUnrestrictedData = (SwitchPreference) findPreference(KEY_UNRESTRICTED_DATA);
159 mUnrestrictedData.setOnPreferenceChangeListener(this);
161 mDataSaverBackend = new DataSaverBackend(getContext());
162 mAppSettings = findPreference(KEY_APP_SETTINGS);
164 mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
165 mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
167 PackageManager pm = getPackageManager();
168 boolean matchFound = false;
169 for (String packageName : mPackages) {
170 mAppSettingsIntent.setPackage(packageName);
171 if (pm.resolveActivity(mAppSettingsIntent, 0) != null) {
177 removePreference(KEY_APP_SETTINGS);
181 if (mPackages.size() > 1) {
182 mAppList = (PreferenceCategory) findPreference(KEY_APP_LIST);
183 for (int i = 1 ; i < mPackages.size(); i++) {
184 new AppPrefLoader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
185 mPackages.valueAt(i));
188 removePreference(KEY_APP_LIST);
191 if (mAppItem.key == TrafficStats.UID_REMOVED) {
192 mLabel = getContext().getString(R.string.data_usage_uninstalled_apps_users);
193 } else if (mAppItem.key == TrafficStats.UID_TETHERING) {
194 mLabel = getContext().getString(R.string.tether_settings_title_all);
196 final int userId = UidDetailProvider.getUserIdForKey(mAppItem.key);
197 final UserManager um = UserManager.get(getActivity());
198 final UserInfo info = um.getUserInfo(userId);
199 final PackageManager pm = getPackageManager();
200 mIcon = Utils.getUserIcon(getActivity(), um, info);
201 mLabel = Utils.getUserLabel(getActivity(), info);
202 mPackageName = getActivity().getPackageName();
204 removePreference(KEY_UNRESTRICTED_DATA);
205 removePreference(KEY_APP_SETTINGS);
206 removePreference(KEY_RESTRICT_BACKGROUND);
207 removePreference(KEY_APP_LIST);
212 public void onDestroy() {
213 TrafficStats.closeQuietly(mStatsSession);
218 public void onResume() {
220 if (mDataSaverBackend != null) {
221 mDataSaverBackend.addListener(this);
223 mPolicy = services.mPolicyEditor.getPolicy(mTemplate);
224 getLoaderManager().restartLoader(LOADER_CHART_DATA,
225 ChartDataLoader.buildArgs(mTemplate, mAppItem), mChartDataCallbacks);
230 public void onPause() {
232 if (mDataSaverBackend != null) {
233 mDataSaverBackend.remListener(this);
238 public boolean onPreferenceChange(Preference preference, Object newValue) {
239 if (preference == mRestrictBackground) {
240 mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
242 } else if (preference == mUnrestrictedData) {
243 mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
250 public boolean onPreferenceTreeClick(Preference preference) {
251 if (preference == mAppSettings) {
252 // TODO: target towards entire UID instead of just first package
253 getActivity().startActivityAsUser(mAppSettingsIntent, new UserHandle(
254 UserHandle.getUserId(mAppItem.key)));
257 return super.onPreferenceTreeClick(preference);
260 private void updatePrefs() {
261 updatePrefs(getAppRestrictBackground(), getUnrestrictData());
264 private void updatePrefs(boolean restrictBackground, boolean unrestrictData) {
265 if (mRestrictBackground != null) {
266 mRestrictBackground.setChecked(!restrictBackground);
268 if (mUnrestrictedData != null) {
269 if (restrictBackground) {
270 mUnrestrictedData.setVisible(false);
272 mUnrestrictedData.setVisible(true);
273 mUnrestrictedData.setChecked(unrestrictData);
278 private void addUid(int uid) {
279 String[] packages = getPackageManager().getPackagesForUid(uid);
280 if (packages != null) {
281 for (int i = 0; i < packages.length; i++) {
282 mPackages.add(packages[i]);
287 private void bindData() {
288 final long backgroundBytes, foregroundBytes;
289 if (mChartData == null || mStart == 0) {
290 backgroundBytes = foregroundBytes = 0;
291 mCycle.setVisible(false);
293 mCycle.setVisible(true);
294 final long now = System.currentTimeMillis();
295 NetworkStatsHistory.Entry entry = null;
296 entry = mChartData.detailDefault.getValues(mStart, mEnd, now, entry);
297 backgroundBytes = entry.rxBytes + entry.txBytes;
298 entry = mChartData.detailForeground.getValues(mStart, mEnd, now, entry);
299 foregroundBytes = entry.rxBytes + entry.txBytes;
301 final long totalBytes = backgroundBytes + foregroundBytes;
302 final Context context = getContext();
304 mTotalUsage.setSummary(Formatter.formatFileSize(context, totalBytes));
305 mForegroundUsage.setSummary(Formatter.formatFileSize(context, foregroundBytes));
306 mBackgroundUsage.setSummary(Formatter.formatFileSize(context, backgroundBytes));
309 private boolean getAppRestrictBackground() {
310 final int uid = mAppItem.key;
311 final int uidPolicy = services.mPolicyManager.getUidPolicy(uid);
312 return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
315 private boolean getUnrestrictData() {
316 if (mDataSaverBackend != null) {
317 return mDataSaverBackend.isWhitelisted(mAppItem.key);
323 public void onViewCreated(View view, Bundle savedInstanceState) {
324 super.onViewCreated(view, savedInstanceState);
326 View header = setPinnedHeaderView(R.layout.app_header);
327 String pkg = mPackages.size() != 0 ? mPackages.valueAt(0) : null;
330 uid = pkg != null ? getPackageManager().getPackageUid(pkg, 0) : 0;
331 } catch (PackageManager.NameNotFoundException e) {
333 AppHeader.setupHeaderView(getActivity(), mIcon, mLabel,
334 pkg, uid, AppHeader.includeAppInfo(this), 0, header, null);
338 protected int getMetricsCategory() {
339 return MetricsEvent.APP_DATA_USAGE;
342 private AdapterView.OnItemSelectedListener mCycleListener =
343 new AdapterView.OnItemSelectedListener() {
345 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
346 final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) mCycle.getSelectedItem();
348 mStart = cycle.start;
354 public void onNothingSelected(AdapterView<?> parent) {
359 private final LoaderManager.LoaderCallbacks<ChartData> mChartDataCallbacks =
360 new LoaderManager.LoaderCallbacks<ChartData>() {
362 public Loader<ChartData> onCreateLoader(int id, Bundle args) {
363 return new ChartDataLoader(getActivity(), mStatsSession, args);
367 public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
369 mCycleAdapter.updateCycleList(mPolicy, mChartData);
374 public void onLoaderReset(Loader<ChartData> loader) {
378 private class AppPrefLoader extends AsyncTask<String, Void, Preference> {
380 protected Preference doInBackground(String... params) {
381 PackageManager pm = getPackageManager();
382 String pkg = params[0];
384 ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
385 Preference preference = new Preference(getPrefContext());
386 preference.setIcon(info.loadIcon(pm));
387 preference.setTitle(info.loadLabel(pm));
388 preference.setSelectable(false);
390 } catch (PackageManager.NameNotFoundException e) {
396 protected void onPostExecute(Preference pref) {
397 if (pref != null && mAppList != null) {
398 mAppList.addPreference(pref);
404 public void onDataSaverChanged(boolean isDataSaving) {
409 public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) {
410 if (mAppItem.uids.get(uid, false)) {
411 updatePrefs(getAppRestrictBackground(), isWhitelisted);
416 public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) {
417 if (mAppItem.uids.get(uid, false)) {
418 updatePrefs(isBlacklisted, getUnrestrictData());