• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
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
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
13  */
14 
15 package com.android.settings.datausage;
16 
17 import static android.net.ConnectivityManager.TYPE_ETHERNET;
18 
19 import android.app.Activity;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.net.ConnectivityManager;
24 import android.net.INetworkStatsSession;
25 import android.net.NetworkPolicyManager;
26 import android.net.NetworkTemplate;
27 import android.net.TrafficStats;
28 import android.net.wifi.WifiConfiguration;
29 import android.net.wifi.WifiManager;
30 import android.os.Bundle;
31 import android.os.RemoteException;
32 import android.os.SystemProperties;
33 import android.os.UserManager;
34 import android.provider.SearchIndexableResource;
35 import android.support.annotation.VisibleForTesting;
36 import android.support.v7.preference.Preference;
37 import android.support.v7.preference.PreferenceScreen;
38 import android.telephony.SubscriptionInfo;
39 import android.telephony.SubscriptionManager;
40 import android.text.BidiFormatter;
41 import android.text.Spannable;
42 import android.text.SpannableString;
43 import android.text.TextUtils;
44 import android.text.format.Formatter;
45 import android.text.style.RelativeSizeSpan;
46 import android.view.Menu;
47 import android.view.MenuInflater;
48 import android.view.MenuItem;
49 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
50 import com.android.settings.R;
51 import com.android.settings.SummaryPreference;
52 import com.android.settings.Utils;
53 import com.android.settings.dashboard.SummaryLoader;
54 import com.android.settings.search.BaseSearchIndexProvider;
55 import com.android.settings.search.Indexable;
56 import com.android.settingslib.NetworkPolicyEditor;
57 import com.android.settingslib.net.DataUsageController;
58 import java.util.ArrayList;
59 import java.util.List;
60 
61 /**
62  * Settings preference fragment that displays data usage summary.
63  *
64  * This class in deprecated use {@link DataPlanUsageSummary}.
65  */
66 @Deprecated
67 public class DataUsageSummary extends DataUsageBase implements Indexable, DataUsageEditController {
68 
69     static final boolean LOGD = false;
70 
71     public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
72 
73     private static final String KEY_STATUS_HEADER = "status_header";
74     private static final String KEY_LIMIT_SUMMARY = "limit_summary";
75 
76     // Mobile data keys
77     public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
78     public static final String KEY_MOBILE_DATA_USAGE_TOGGLE = "data_usage_enable";
79     public static final String KEY_MOBILE_DATA_USAGE = "cellular_data_usage";
80     public static final String KEY_MOBILE_BILLING_CYCLE = "billing_preference";
81 
82     // Wifi keys
83     public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
84     public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
85     public static final String KEY_NETWORK_RESTRICTIONS = "network_restrictions";
86 
87 
88     private DataUsageController mDataUsageController;
89     private DataUsageInfoController mDataInfoController;
90     private SummaryPreference mSummaryPreference;
91     private Preference mLimitPreference;
92     private NetworkTemplate mDefaultTemplate;
93     private int mDataUsageTemplate;
94     private NetworkRestrictionsPreference mNetworkRestrictionPreference;
95     private WifiManager mWifiManager;
96     private NetworkPolicyEditor mPolicyEditor;
97 
98     @Override
getHelpResource()99     protected int getHelpResource() {
100         return R.string.help_url_data_usage;
101     }
102 
103     @Override
onCreate(Bundle icicle)104     public void onCreate(Bundle icicle) {
105         super.onCreate(icicle);
106 
107         final Context context = getContext();
108         NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
109         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
110         mPolicyEditor = new NetworkPolicyEditor(policyManager);
111 
112         boolean hasMobileData = DataUsageUtils.hasMobileData(context);
113         mDataUsageController = new DataUsageController(context);
114         mDataInfoController = new DataUsageInfoController();
115         addPreferencesFromResource(R.xml.data_usage);
116 
117         int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
118         if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
119             hasMobileData = false;
120         }
121         mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
122         mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER);
123 
124         if (!hasMobileData || !isAdmin()) {
125             removePreference(KEY_RESTRICT_BACKGROUND);
126         }
127         if (hasMobileData) {
128             mLimitPreference = findPreference(KEY_LIMIT_SUMMARY);
129             List<SubscriptionInfo> subscriptions =
130                     services.mSubscriptionManager.getActiveSubscriptionInfoList();
131             if (subscriptions == null || subscriptions.size() == 0) {
132                 addMobileSection(defaultSubId);
133             }
134             for (int i = 0; subscriptions != null && i < subscriptions.size(); i++) {
135                 SubscriptionInfo subInfo = subscriptions.get(i);
136                 if (subscriptions.size() > 1) {
137                     addMobileSection(subInfo.getSubscriptionId(), subInfo);
138                 } else {
139                     addMobileSection(subInfo.getSubscriptionId());
140                 }
141             }
142             mSummaryPreference.setSelectable(true);
143         } else {
144             removePreference(KEY_LIMIT_SUMMARY);
145             mSummaryPreference.setSelectable(false);
146         }
147         boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
148         if (hasWifiRadio) {
149             addWifiSection();
150         }
151         if (hasEthernet(context)) {
152             addEthernetSection();
153         }
154         mDataUsageTemplate = hasMobileData ? R.string.cell_data_template
155                 : hasWifiRadio ? R.string.wifi_data_template
156                 : R.string.ethernet_data_template;
157 
158         setHasOptionsMenu(true);
159     }
160 
161     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)162     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
163         if (UserManager.get(getContext()).isAdminUser()) {
164             inflater.inflate(R.menu.data_usage, menu);
165         }
166         super.onCreateOptionsMenu(menu, inflater);
167     }
168 
169     @Override
onOptionsItemSelected(MenuItem item)170     public boolean onOptionsItemSelected(MenuItem item) {
171         switch (item.getItemId()) {
172             case R.id.data_usage_menu_cellular_networks: {
173                 final Intent intent = new Intent(Intent.ACTION_MAIN);
174                 intent.setComponent(new ComponentName("com.android.phone",
175                         "com.android.phone.MobileNetworkSettings"));
176                 startActivity(intent);
177                 return true;
178             }
179         }
180         return false;
181     }
182 
183     @Override
onPreferenceTreeClick(Preference preference)184     public boolean onPreferenceTreeClick(Preference preference) {
185         if (preference == findPreference(KEY_STATUS_HEADER)) {
186             BillingCycleSettings.BytesEditorFragment.show(this, false);
187             return false;
188         }
189         return super.onPreferenceTreeClick(preference);
190     }
191 
addMobileSection(int subId)192     private void addMobileSection(int subId) {
193         addMobileSection(subId, null);
194     }
195 
addMobileSection(int subId, SubscriptionInfo subInfo)196     private void addMobileSection(int subId, SubscriptionInfo subInfo) {
197         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
198                 inflatePreferences(R.xml.data_usage_cellular);
199         category.setTemplate(getNetworkTemplate(subId), subId, services);
200         category.pushTemplates(services);
201         if (subInfo != null && !TextUtils.isEmpty(subInfo.getDisplayName())) {
202             Preference title  = category.findPreference(KEY_MOBILE_USAGE_TITLE);
203             title.setTitle(subInfo.getDisplayName());
204         }
205     }
206 
addWifiSection()207     private void addWifiSection() {
208         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
209                 inflatePreferences(R.xml.data_usage_wifi);
210         category.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0, services);
211         mNetworkRestrictionPreference =
212             (NetworkRestrictionsPreference) category.findPreference(KEY_NETWORK_RESTRICTIONS);
213     }
214 
addEthernetSection()215     private void addEthernetSection() {
216         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
217                 inflatePreferences(R.xml.data_usage_ethernet);
218         category.setTemplate(NetworkTemplate.buildTemplateEthernet(), 0, services);
219     }
220 
inflatePreferences(int resId)221     private Preference inflatePreferences(int resId) {
222         PreferenceScreen rootPreferences = getPreferenceManager().inflateFromResource(
223                 getPrefContext(), resId, null);
224         Preference pref = rootPreferences.getPreference(0);
225         rootPreferences.removeAll();
226 
227         PreferenceScreen screen = getPreferenceScreen();
228         pref.setOrder(screen.getPreferenceCount());
229         screen.addPreference(pref);
230 
231         return pref;
232     }
233 
getNetworkTemplate(int subscriptionId)234     private NetworkTemplate getNetworkTemplate(int subscriptionId) {
235         NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll(
236                 services.mTelephonyManager.getSubscriberId(subscriptionId));
237         return NetworkTemplate.normalize(mobileAll,
238                 services.mTelephonyManager.getMergedSubscriberIds());
239     }
240 
241     @Override
onResume()242     public void onResume() {
243         super.onResume();
244         updateState();
245     }
246 
formatTitle(Context context, String template, long usageLevel)247     private static CharSequence formatTitle(Context context, String template, long usageLevel) {
248         final float LARGER_SIZE = 1.25f * 1.25f;  // (1/0.8)^2
249         final float SMALLER_SIZE = 1.0f / LARGER_SIZE;  // 0.8^2
250         final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
251 
252         final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
253                 usageLevel, Formatter.FLAG_SHORTER);
254         final SpannableString enlargedValue = new SpannableString(usedResult.value);
255         enlargedValue.setSpan(new RelativeSizeSpan(LARGER_SIZE), 0, enlargedValue.length(), FLAGS);
256 
257         final SpannableString amountTemplate = new SpannableString(
258                 context.getString(com.android.internal.R.string.fileSizeSuffix)
259                 .replace("%1$s", "^1").replace("%2$s", "^2"));
260         final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate,
261                 enlargedValue, usedResult.units);
262 
263         final SpannableString fullTemplate = new SpannableString(template);
264         fullTemplate.setSpan(new RelativeSizeSpan(SMALLER_SIZE), 0, fullTemplate.length(), FLAGS);
265         return TextUtils.expandTemplate(fullTemplate,
266                 BidiFormatter.getInstance().unicodeWrap(formattedUsage));
267     }
268 
updateState()269     private void updateState() {
270         DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
271                 mDefaultTemplate);
272         Context context = getContext();
273         mDataInfoController.updateDataLimit(info,
274                 services.mPolicyEditor.getPolicy(mDefaultTemplate));
275 
276         if (mSummaryPreference != null) {
277             mSummaryPreference.setTitle(
278                     formatTitle(context, getString(mDataUsageTemplate), info.usageLevel));
279             long limit = mDataInfoController.getSummaryLimit(info);
280             mSummaryPreference.setSummary(info.period);
281 
282             if (limit <= 0) {
283                 mSummaryPreference.setChartEnabled(false);
284             } else {
285                 mSummaryPreference.setChartEnabled(true);
286                 mSummaryPreference.setLabels(Formatter.formatFileSize(context, 0),
287                         Formatter.formatFileSize(context, limit));
288                 mSummaryPreference.setRatios(info.usageLevel / (float) limit, 0,
289                         (limit - info.usageLevel) / (float) limit);
290             }
291         }
292         if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) {
293             String warning = Formatter.formatFileSize(context, info.warningLevel);
294             String limit = Formatter.formatFileSize(context, info.limitLevel);
295             mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only
296                     : R.string.cell_warning_and_limit, warning, limit));
297         } else if (mLimitPreference != null) {
298             mLimitPreference.setSummary(null);
299         }
300 
301         updateNetworkRestrictionSummary(mNetworkRestrictionPreference);
302 
303         PreferenceScreen screen = getPreferenceScreen();
304         for (int i = 1; i < screen.getPreferenceCount(); i++) {
305             ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
306         }
307     }
308 
309     @Override
getMetricsCategory()310     public int getMetricsCategory() {
311         return MetricsEvent.DATA_USAGE_SUMMARY;
312     }
313 
314     @Override
getNetworkPolicyEditor()315     public NetworkPolicyEditor getNetworkPolicyEditor() {
316         return services.mPolicyEditor;
317     }
318 
319     @Override
getNetworkTemplate()320     public NetworkTemplate getNetworkTemplate() {
321         return mDefaultTemplate;
322     }
323 
324     @Override
updateDataUsage()325     public void updateDataUsage() {
326         updateState();
327     }
328 
329     @VisibleForTesting
updateNetworkRestrictionSummary(NetworkRestrictionsPreference preference)330     void updateNetworkRestrictionSummary(NetworkRestrictionsPreference preference) {
331         if (preference == null) {
332             return;
333         }
334         mPolicyEditor.read();
335         int count = 0;
336         for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
337             if (WifiConfiguration.isMetered(config, null)) {
338                 count++;
339             }
340         }
341         preference.setSummary(getResources().getQuantityString(
342             R.plurals.network_restrictions_summary, count, count));
343     }
344 
345     private static class SummaryProvider
346             implements SummaryLoader.SummaryProvider {
347 
348         private final Activity mActivity;
349         private final SummaryLoader mSummaryLoader;
350         private final DataUsageController mDataController;
351 
SummaryProvider(Activity activity, SummaryLoader summaryLoader)352         public SummaryProvider(Activity activity, SummaryLoader summaryLoader) {
353             mActivity = activity;
354             mSummaryLoader = summaryLoader;
355             mDataController = new DataUsageController(activity);
356         }
357 
358         @Override
setListening(boolean listening)359         public void setListening(boolean listening) {
360             if (listening) {
361                 DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
362                 String used;
363                 if (info == null) {
364                     used = Formatter.formatFileSize(mActivity, 0);
365                 } else if (info.limitLevel <= 0) {
366                     used = Formatter.formatFileSize(mActivity, info.usageLevel);
367                 } else {
368                     used = Utils.formatPercentage(info.usageLevel, info.limitLevel);
369                 }
370                 mSummaryLoader.setSummary(this,
371                         mActivity.getString(R.string.data_usage_summary_format, used));
372             }
373         }
374     }
375 
376     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
377         = SummaryProvider::new;
378 
379     /**
380      * For search
381      */
382     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
383         new BaseSearchIndexProvider() {
384 
385             @Override
386             public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
387                     boolean enabled) {
388                 List<SearchIndexableResource> resources = new ArrayList<>();
389                 SearchIndexableResource resource = new SearchIndexableResource(context);
390                 resource.xmlResId = R.xml.data_usage;
391                 resources.add(resource);
392 
393                 resource = new SearchIndexableResource(context);
394                 resource.xmlResId = R.xml.data_usage_cellular;
395                 resources.add(resource);
396 
397                 resource = new SearchIndexableResource(context);
398                 resource.xmlResId = R.xml.data_usage_wifi;
399                 resources.add(resource);
400 
401                 return resources;
402             }
403 
404             @Override
405             public List<String> getNonIndexableKeys(Context context) {
406                 List<String> keys = super.getNonIndexableKeys(context);
407 
408                 if (!DataUsageUtils.hasMobileData(context)) {
409                     keys.add(KEY_MOBILE_USAGE_TITLE);
410                     keys.add(KEY_MOBILE_DATA_USAGE_TOGGLE);
411                     keys.add(KEY_MOBILE_DATA_USAGE);
412                     keys.add(KEY_MOBILE_BILLING_CYCLE);
413                 }
414 
415                 if (!DataUsageUtils.hasWifiRadio(context)) {
416                     keys.add(KEY_WIFI_DATA_USAGE);
417                     keys.add(KEY_NETWORK_RESTRICTIONS);
418                 }
419 
420                 // This title is named Wifi, and will confuse users.
421                 keys.add(KEY_WIFI_USAGE_TITLE);
422 
423                 return keys;
424             }
425         };
426 }
427