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