• 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 android.app.Activity;
18 import android.app.settings.SettingsEnums;
19 import android.content.Context;
20 import android.net.NetworkTemplate;
21 import android.os.Bundle;
22 import android.telephony.SubscriptionInfo;
23 import android.telephony.SubscriptionManager;
24 import android.text.BidiFormatter;
25 import android.text.Spannable;
26 import android.text.SpannableString;
27 import android.text.TextUtils;
28 import android.text.format.Formatter;
29 import android.text.style.RelativeSizeSpan;
30 
31 import androidx.annotation.VisibleForTesting;
32 import androidx.preference.Preference;
33 import androidx.preference.PreferenceScreen;
34 
35 import com.android.settings.R;
36 import com.android.settings.datausage.lib.DataUsageLib;
37 import com.android.settings.network.ProxySubscriptionManager;
38 import com.android.settings.network.SubscriptionUtil;
39 import com.android.settingslib.NetworkPolicyEditor;
40 import com.android.settingslib.core.AbstractPreferenceController;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 /**
46  * Settings preference fragment that displays data usage summary.
47  */
48 public class DataUsageSummary extends DataUsageBaseFragment implements DataUsageEditController {
49 
50     private static final String TAG = "DataUsageSummary";
51 
52     static final boolean LOGD = false;
53 
54     public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
55 
56     private static final String KEY_STATUS_HEADER = "status_header";
57 
58     // Mobile data keys
59     public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
60     public static final String KEY_MOBILE_DATA_USAGE_TOGGLE = "data_usage_enable";
61     public static final String KEY_MOBILE_DATA_USAGE = "cellular_data_usage";
62     public static final String KEY_MOBILE_BILLING_CYCLE = "billing_preference";
63 
64     // Wifi keys
65     public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
66     public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
67 
68     private DataUsageSummaryPreference mSummaryPreference;
69     private DataUsageSummaryPreferenceController mSummaryController;
70     private NetworkTemplate mDefaultTemplate;
71     private ProxySubscriptionManager mProxySubscriptionMgr;
72 
73     @Override
getHelpResource()74     public int getHelpResource() {
75         return R.string.help_url_data_usage;
76     }
77 
78     @Override
onCreate(Bundle icicle)79     public void onCreate(Bundle icicle) {
80         super.onCreate(icicle);
81         Context context = getContext();
82 
83         enableProxySubscriptionManager(context);
84 
85         boolean hasMobileData = DataUsageUtils.hasMobileData(context);
86 
87         final int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
88         if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
89             hasMobileData = false;
90         }
91         mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
92         mSummaryPreference = findPreference(KEY_STATUS_HEADER);
93 
94         if (!hasMobileData || !isAdmin()) {
95             removePreference(KEY_RESTRICT_BACKGROUND);
96         }
97         boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
98         if (hasMobileData) {
99             addMobileSection(defaultSubId);
100             if (hasActiveSubscription() && hasWifiRadio) {
101                 // If the device has active SIM, the data usage section shows usage for mobile,
102                 // and the WiFi section is added if there is a WiFi radio - legacy behavior.
103                 addWifiSection();
104             }
105             // Do not add the WiFi section if either there is no WiFi radio (obviously) or if no
106             // SIM is installed. In the latter case the data usage section will show WiFi usage and
107             // there should be no explicit WiFi section added.
108         } else if (hasWifiRadio) {
109             addWifiSection();
110         }
111         if (DataUsageUtils.hasEthernet(context)) {
112             addEthernetSection();
113         }
114         setHasOptionsMenu(true);
115     }
116 
117     @Override
onPreferenceTreeClick(Preference preference)118     public boolean onPreferenceTreeClick(Preference preference) {
119         if (preference == findPreference(KEY_STATUS_HEADER)) {
120             BillingCycleSettings.BytesEditorFragment.show(this, false);
121             return false;
122         }
123         return super.onPreferenceTreeClick(preference);
124     }
125 
126     @Override
getPreferenceScreenResId()127     protected int getPreferenceScreenResId() {
128         return R.xml.data_usage;
129     }
130 
131     @Override
getLogTag()132     protected String getLogTag() {
133         return TAG;
134     }
135 
136     @Override
createPreferenceControllers(Context context)137     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
138         final Activity activity = getActivity();
139         final ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
140         mSummaryController =
141                 new DataUsageSummaryPreferenceController(activity, getSettingsLifecycle(), this,
142                         DataUsageUtils.getDefaultSubscriptionId(activity));
143         controllers.add(mSummaryController);
144         getSettingsLifecycle().addObserver(mSummaryController);
145         return controllers;
146     }
147 
148     @VisibleForTesting
addMobileSection(int subId)149     void addMobileSection(int subId) {
150         addMobileSection(subId, null);
151     }
152 
153     @VisibleForTesting
enableProxySubscriptionManager(Context context)154     void enableProxySubscriptionManager(Context context) {
155         // Enable ProxySubscriptionMgr with Lifecycle support for all controllers
156         // live within this fragment
157         mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(context);
158         mProxySubscriptionMgr.setLifecycle(getLifecycle());
159     }
160 
161     @VisibleForTesting
hasActiveSubscription()162     boolean hasActiveSubscription() {
163         final List<SubscriptionInfo> subInfoList =
164                 mProxySubscriptionMgr.getActiveSubscriptionsInfo();
165         return ((subInfoList != null) && (subInfoList.size() > 0));
166     }
167 
addMobileSection(int subId, SubscriptionInfo subInfo)168     private void addMobileSection(int subId, SubscriptionInfo subInfo) {
169         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
170                 inflatePreferences(R.xml.data_usage_cellular);
171         category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId),
172                 subId, services);
173         category.pushTemplates(services);
174         final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
175                 subInfo, getContext());
176         if (subInfo != null && !TextUtils.isEmpty(displayName)) {
177             Preference title  = category.findPreference(KEY_MOBILE_USAGE_TITLE);
178             title.setTitle(displayName);
179         }
180     }
181 
182     @VisibleForTesting
addWifiSection()183     void addWifiSection() {
184         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
185                 inflatePreferences(R.xml.data_usage_wifi);
186         category.setTemplate(
187                 NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
188                 null /* subscriberId */), 0, services);
189     }
190 
addEthernetSection()191     private void addEthernetSection() {
192         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
193                 inflatePreferences(R.xml.data_usage_ethernet);
194         category.setTemplate(NetworkTemplate.buildTemplateEthernet(), 0, services);
195     }
196 
inflatePreferences(int resId)197     private Preference inflatePreferences(int resId) {
198         PreferenceScreen rootPreferences = getPreferenceManager().inflateFromResource(
199                 getPrefContext(), resId, null);
200         Preference pref = rootPreferences.getPreference(0);
201         rootPreferences.removeAll();
202 
203         PreferenceScreen screen = getPreferenceScreen();
204         pref.setOrder(screen.getPreferenceCount());
205         screen.addPreference(pref);
206 
207         return pref;
208     }
209 
210     @Override
onResume()211     public void onResume() {
212         super.onResume();
213         updateState();
214     }
215 
216     @VisibleForTesting
formatUsage(Context context, String template, long usageLevel)217     static CharSequence formatUsage(Context context, String template, long usageLevel) {
218         final float LARGER_SIZE = 1.25f * 1.25f;  // (1/0.8)^2
219         final float SMALLER_SIZE = 1.0f / LARGER_SIZE;  // 0.8^2
220         return formatUsage(context, template, usageLevel, LARGER_SIZE, SMALLER_SIZE);
221     }
222 
formatUsage(Context context, String template, long usageLevel, float larger, float smaller)223     static CharSequence formatUsage(Context context, String template, long usageLevel,
224                                     float larger, float smaller) {
225         final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
226 
227         final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
228                 usageLevel, Formatter.FLAG_CALCULATE_ROUNDED | Formatter.FLAG_IEC_UNITS);
229         final SpannableString enlargedValue = new SpannableString(usedResult.value);
230         enlargedValue.setSpan(new RelativeSizeSpan(larger), 0, enlargedValue.length(), FLAGS);
231 
232         final SpannableString amountTemplate = new SpannableString(
233                 context.getString(com.android.internal.R.string.fileSizeSuffix)
234                 .replace("%1$s", "^1").replace("%2$s", "^2"));
235         final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate,
236                 enlargedValue, usedResult.units);
237 
238         final SpannableString fullTemplate = new SpannableString(template);
239         fullTemplate.setSpan(new RelativeSizeSpan(smaller), 0, fullTemplate.length(), FLAGS);
240         return TextUtils.expandTemplate(fullTemplate,
241                 BidiFormatter.getInstance().unicodeWrap(formattedUsage.toString()));
242     }
243 
updateState()244     private void updateState() {
245         PreferenceScreen screen = getPreferenceScreen();
246         for (int i = 1; i < screen.getPreferenceCount(); i++) {
247           Preference currentPreference = screen.getPreference(i);
248           if (currentPreference instanceof TemplatePreferenceCategory) {
249             ((TemplatePreferenceCategory) currentPreference).pushTemplates(services);
250           }
251         }
252     }
253 
254     @Override
getMetricsCategory()255     public int getMetricsCategory() {
256         return SettingsEnums.DATA_USAGE_SUMMARY;
257     }
258 
259     @Override
getNetworkPolicyEditor()260     public NetworkPolicyEditor getNetworkPolicyEditor() {
261         return services.mPolicyEditor;
262     }
263 
264     @Override
getNetworkTemplate()265     public NetworkTemplate getNetworkTemplate() {
266         return mDefaultTemplate;
267     }
268 
269     @Override
updateDataUsage()270     public void updateDataUsage() {
271         updateState();
272         mSummaryController.updateState(mSummaryPreference);
273     }
274 }
275