1/* 2 * Copyright (C) 2017 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 15package com.android.settings.datausage; 16 17import static android.net.NetworkPolicy.LIMIT_DISABLED; 18 19import android.annotation.IdRes; 20import android.app.Activity; 21import android.content.Context; 22import android.content.Intent; 23import android.net.NetworkPolicy; 24import android.net.NetworkPolicyManager; 25import android.net.NetworkTemplate; 26import android.net.wifi.WifiConfiguration; 27import android.net.wifi.WifiManager; 28import android.os.Bundle; 29import android.os.UserManager; 30import android.provider.Settings; 31import android.support.annotation.VisibleForTesting; 32import android.support.v7.preference.Preference; 33import android.support.v7.preference.PreferenceCategory; 34import android.support.v7.preference.PreferenceScreen; 35import android.telephony.SubscriptionInfo; 36import android.telephony.SubscriptionManager; 37import android.text.TextUtils; 38import android.text.format.Formatter; 39import android.view.Menu; 40import android.view.MenuInflater; 41import android.view.MenuItem; 42import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 43import com.android.settings.R; 44import com.android.settings.Utils; 45import com.android.settings.dashboard.SummaryLoader; 46import com.android.settingslib.NetworkPolicyEditor; 47import com.android.settingslib.net.DataUsageController; 48import java.util.ArrayList; 49import java.util.List; 50 51public class DataPlanUsageSummary extends DataUsageBase { 52 53 public static final String KEY_DATA_PLAN_USAGE = "data_plan_usage"; 54 55 public static final String KEY_STATUS_HEADER = "status_header"; 56 public static final String KEY_LIMIT_SUMMARY = "plan_summary"; 57 58 // Mobile data keys 59 public static final String KEY_MOBILE_USAGE_TITLE = "data_usage_mobile_category"; 60 public static final String KEY_MOBILE_DATA_USAGE_TOGGLE = "data_usage_enable"; 61 62 // Wifi keys 63 public static final String KEY_WIFI_USAGE_TITLE = "wifi_category"; 64 public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage"; 65 public static final String KEY_NETWORK_RESTRICTIONS = "network_restrictions"; 66 67 private DataUsageController mDataUsageController; 68 private DataUsageInfoController mDataInfoController; 69 private List<DataPlanSummaryPreference> mDataPlanSummaryPreferenceList; 70 private Preference mLimitPreference; 71 private NetworkTemplate mDefaultTemplate; 72 private NetworkRestrictionsPreference mNetworkRestrictionPreference; 73 private WifiManager mWifiManager; 74 private NetworkPolicyEditor mPolicyEditor; 75 76 @Override 77 protected int getHelpResource() { 78 return R.string.help_url_data_usage; 79 } 80 81 @Override 82 public void onCreate(Bundle bundle) { 83 super.onCreate(bundle); 84 85 final Context context = getContext(); 86 NetworkPolicyManager policyManager = NetworkPolicyManager.from(context); 87 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 88 mPolicyEditor = new NetworkPolicyEditor(policyManager); 89 mDataUsageController = new DataUsageController(context); 90 mDataInfoController = new DataUsageInfoController(); 91 92 int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context); 93 boolean hasMobileData = DataUsageUtils.hasMobileData(context); 94 if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 95 hasMobileData = false; 96 } 97 mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId); 98 99 if (hasMobileData) { 100 addDataPlanSection(defaultSubId); 101 } 102 103 if (DataUsageUtils.hasWifiRadio(context)) { 104 addWifiSection(); 105 } 106 107 if (hasEthernet(context)) { 108 addEthernetSection(); 109 } 110 setHasOptionsMenu(true); 111 } 112 113 @Override 114 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 115 if (UserManager.get(getContext()).isAdminUser()) { 116 inflater.inflate(R.menu.data_usage, menu); 117 } 118 super.onCreateOptionsMenu(menu, inflater); 119 } 120 121 @Override 122 public boolean onOptionsItemSelected(MenuItem item) { 123 switch (item.getItemId()) { 124 case R.id.data_usage_menu_cellular_networks: { 125 final Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); 126 startActivity(intent); 127 return true; 128 } 129 } 130 return false; 131 } 132 133 private void addDataPlanSection(int defaultSubId) { 134 Context context = getPrefContext(); 135 addPreferencesFromResource(R.xml.data_plan_usage); 136 PreferenceScreen screen = getPreferenceScreen(); 137 screen.setTitle(context.getString(R.string.data_usage_summary_title)); 138 139 PreferenceCategory preferenceCategory = 140 (PreferenceCategory) findPreference(KEY_DATA_PLAN_USAGE); 141 screen.addPreference(preferenceCategory); 142 143 Preference dataPlansSyncTimePreference = new Preference(context); 144 dataPlansSyncTimePreference.setLayoutResource(R.layout.data_plans_sync_time_preference); 145 dataPlansSyncTimePreference.setTitle(MockDataPlanUsage.SYNC_TIME); 146 preferenceCategory.addPreference(dataPlansSyncTimePreference); 147 148 mDataPlanSummaryPreferenceList = new ArrayList<>(MockDataPlanUsage.DATA_PLAN_USAGES.length); 149 for (int i = 0; i < MockDataPlanUsage.DATA_PLAN_USAGES.length; i++) { 150 DataPlanSummaryPreference dataPlanSummaryPreference = 151 new DataPlanSummaryPreference(context); 152 dataPlanSummaryPreference.setKey(KEY_STATUS_HEADER + (i + 1)); 153 mDataPlanSummaryPreferenceList.add(dataPlanSummaryPreference); 154 preferenceCategory.addPreference(dataPlanSummaryPreference); 155 } 156 157 Preference preference = new Preference(context); 158 preference.setLayoutResource(R.layout.manage_data_plans_preference); 159 preferenceCategory.addPreference(preference); 160 setPreferenceScreen(screen); 161 162 mLimitPreference = findPreference(KEY_LIMIT_SUMMARY); 163 List<SubscriptionInfo> subscriptions = 164 services.mSubscriptionManager.getActiveSubscriptionInfoList(); 165 166 if (subscriptions == null || subscriptions.isEmpty()) { 167 addMobileSection(defaultSubId); 168 } 169 170 for (int i = 0, subscriptionsSize = subscriptions != null ? subscriptions.size() : 0; 171 i < subscriptionsSize; i++) { 172 SubscriptionInfo subInfo = subscriptions.get(i); 173 if (subscriptionsSize > 1) { 174 addMobileSection(subInfo.getSubscriptionId(), subInfo); 175 } else { 176 addMobileSection(subInfo.getSubscriptionId()); 177 } 178 } 179 } 180 181 private void addMobileSection(int subId) { 182 addMobileSection(subId, null); 183 } 184 185 private void addMobileSection(int subId, SubscriptionInfo subInfo) { 186 TemplatePreferenceCategory category = (TemplatePreferenceCategory) 187 inflatePreferences(R.xml.data_plan_usage_cell_data_preference_screen); 188 category.setTemplate(getNetworkTemplate(subId), subId, services); 189 category.pushTemplates(services); 190 if (subInfo != null && !TextUtils.isEmpty(subInfo.getDisplayName())) { 191 Preference title = category.findPreference(KEY_MOBILE_USAGE_TITLE); 192 title.setTitle(subInfo.getDisplayName()); 193 } 194 } 195 196 private void addWifiSection() { 197 TemplatePreferenceCategory category = (TemplatePreferenceCategory) 198 inflatePreferences(R.xml.data_usage_wifi); 199 category.setTemplate(NetworkTemplate.buildTemplateWifiWildcard(), 0 /* subId */, services); 200 mNetworkRestrictionPreference = 201 (NetworkRestrictionsPreference) category.findPreference(KEY_NETWORK_RESTRICTIONS); 202 } 203 204 private void addEthernetSection() { 205 TemplatePreferenceCategory category = (TemplatePreferenceCategory) 206 inflatePreferences(R.xml.data_usage_ethernet); 207 category.setTemplate(NetworkTemplate.buildTemplateEthernet(), 0 /* subId */, services); 208 } 209 210 private Preference inflatePreferences(@IdRes int resId) { 211 PreferenceScreen rootPreferences = getPreferenceManager().inflateFromResource( 212 getPrefContext(), resId, null); 213 Preference pref = rootPreferences.getPreference(0); 214 rootPreferences.removeAll(); 215 216 PreferenceScreen screen = getPreferenceScreen(); 217 pref.setOrder(screen.getPreferenceCount()); 218 screen.addPreference(pref); 219 220 return pref; 221 } 222 223 private NetworkTemplate getNetworkTemplate(int subscriptionId) { 224 NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( 225 services.mTelephonyManager.getSubscriberId(subscriptionId)); 226 return NetworkTemplate.normalize(mobileAll, 227 services.mTelephonyManager.getMergedSubscriberIds()); 228 } 229 230 @Override 231 public void onResume() { 232 super.onResume(); 233 updateState(); 234 } 235 236 private void updateState() { 237 DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo( 238 mDefaultTemplate); 239 240 Context context = getContext(); 241 mDataInfoController.updateDataLimit(info, 242 services.mPolicyEditor.getPolicy(mDefaultTemplate)); 243 244 // TODO(b/63391323): Get rid of MockDataPlanUsage once we integrate with data plan APIs 245 if (mDataPlanSummaryPreferenceList != null && !mDataPlanSummaryPreferenceList.isEmpty()) { 246 MockDataPlanUsage[] dataPlanUsages = MockDataPlanUsage.getDataPlanUsage(); 247 for (int i = 0; i < dataPlanUsages.length; i++) { 248 DataPlanSummaryPreference dataPlanSummaryPreference = 249 mDataPlanSummaryPreferenceList.get(i); 250 MockDataPlanUsage dataPlanUsage = dataPlanUsages[i]; 251 dataPlanSummaryPreference.setTitle(dataPlanUsage.mUsage); 252 dataPlanSummaryPreference.setUsageTextColor(dataPlanUsage.mUsageTextColor); 253 dataPlanSummaryPreference.setName(dataPlanUsage.mName); 254 dataPlanSummaryPreference.setPercentageUsage(dataPlanUsage.mPercentageUsage); 255 dataPlanSummaryPreference 256 .setMeterBackgroundColor(dataPlanUsage.mMeterBackgroundColor); 257 dataPlanSummaryPreference.setMeterConsumedColor(dataPlanUsage.mMeterConsumedColor); 258 dataPlanSummaryPreference.setDescription(dataPlanUsage.mDescription); 259 } 260 } 261 262 if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) { 263 String warning = Formatter.formatFileSize(context, info.warningLevel); 264 String limit = Formatter.formatFileSize(context, info.limitLevel); 265 mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only 266 : R.string.cell_warning_and_limit, warning, limit)); 267 } else if (mLimitPreference != null) { 268 mLimitPreference.setSummary(null); 269 } 270 271 updateNetworkRestrictionSummary(mNetworkRestrictionPreference); 272 273 PreferenceScreen screen = getPreferenceScreen(); 274 for (int i = 1, preferenceCount = screen.getPreferenceCount(); i < preferenceCount; i++) { 275 ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services); 276 } 277 } 278 279 @Override 280 public int getMetricsCategory() { 281 return MetricsEvent.DATA_USAGE_SUMMARY; 282 } 283 284 @VisibleForTesting 285 void updateNetworkRestrictionSummary(NetworkRestrictionsPreference preference) { 286 if (preference == null) { 287 return; 288 } 289 mPolicyEditor.read(); 290 int count = 0; 291 List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks(); 292 for (int i = 0, configuredNetworksSize = configuredNetworks.size(); 293 i < configuredNetworksSize; i++) { 294 WifiConfiguration config = configuredNetworks.get(i); 295 if (isMetered(config)) { 296 count++; 297 } 298 } 299 preference.setSummary(getResources().getQuantityString( 300 R.plurals.network_restrictions_summary, count, count)); 301 } 302 303 @VisibleForTesting 304 boolean isMetered(WifiConfiguration config) { 305 if (config.SSID == null) { 306 return false; 307 } 308 final String networkId = config.isPasspoint() ? config.providerFriendlyName : config.SSID; 309 final NetworkPolicy policy = 310 mPolicyEditor.getPolicyMaybeUnquoted(NetworkTemplate.buildTemplateWifi(networkId)); 311 if (policy == null) { 312 return false; 313 } 314 if (policy.limitBytes != LIMIT_DISABLED) { 315 return true; 316 } 317 return policy.metered; 318 } 319 320 private static class SummaryProvider 321 implements SummaryLoader.SummaryProvider { 322 323 private final Activity mActivity; 324 private final SummaryLoader mSummaryLoader; 325 private final DataUsageController mDataController; 326 327 public SummaryProvider(Activity activity, SummaryLoader summaryLoader) { 328 mActivity = activity; 329 mSummaryLoader = summaryLoader; 330 mDataController = new DataUsageController(activity); 331 } 332 333 @Override 334 public void setListening(boolean listening) { 335 if (listening) { 336 DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo(); 337 String used; 338 if (info == null) { 339 used = Formatter.formatFileSize(mActivity, 0); 340 } else if (info.limitLevel <= 0) { 341 used = Formatter.formatFileSize(mActivity, info.usageLevel); 342 } else { 343 used = Utils.formatPercentage(info.usageLevel, info.limitLevel); 344 } 345 mSummaryLoader.setSummary(this, 346 mActivity.getString(R.string.data_usage_summary_format, used)); 347 } 348 } 349 } 350 351 public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY 352 = SummaryProvider::new; 353} 354 355