Update DataUsageSummary to include carrier provided information.
This CL augments the existing data usage display with carrier provided information about data usage and plans when available from the new frameworks API. Test: manual Test: make RunSettingsRoboTests Bug: 70950124 Change-Id: Idde1ff786e8c5dbc04e58ffbcc0fd18789682699
This commit is contained in:
committed by
Eric Schwarzenbach
parent
525d757c09
commit
4fbe0f8354
112
res/layout/data_usage_summary_preference.xml
Normal file
112
res/layout/data_usage_summary_preference.xml
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2018 The Android Open Source Project
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at"+
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/preference_no_icon_padding_start"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/selectable_card_grey"
|
||||||
|
android:selectable="false"
|
||||||
|
style="@style/EntityHeader">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/usage_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:text="@string/data_usage_title" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:fontFamily="@*android:string/config_headlineFontFamily"
|
||||||
|
android:textColor="?android:attr/colorAccent"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.Material.Large" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:paddingBottom="5dp" />
|
||||||
|
|
||||||
|
<com.android.settings.widget.LinearColorBar
|
||||||
|
android:id="@+id/color_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="28dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/label_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="2dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView android:id="@android:id/text1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<TextView android:id="@android:id/text2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cycle_left_time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="5dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/carrier_and_update"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="5dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/launch_mdp_app_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left"
|
||||||
|
android:text="@string/launch_mdp_app_text"
|
||||||
|
style="@style/ActionPrimaryButton" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/data_limits"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="5dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
@@ -5844,6 +5844,8 @@
|
|||||||
<string name="data_usage_enable_3g">2G-3G data</string>
|
<string name="data_usage_enable_3g">2G-3G data</string>
|
||||||
<!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] -->
|
<!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] -->
|
||||||
<string name="data_usage_enable_4g">4G data</string>
|
<string name="data_usage_enable_4g">4G data</string>
|
||||||
|
<!-- Toggle switch title for enabling roaming on the primary data SIM card. [CHAR LIMIT=32] -->
|
||||||
|
<string name="data_roaming_enable_mobile">Roaming</string>
|
||||||
|
|
||||||
<!-- Data Usage Foreground label. [CHAR LIMIT=40] -->
|
<!-- Data Usage Foreground label. [CHAR LIMIT=40] -->
|
||||||
<string name="data_usage_forground_label">Foreground:</string>
|
<string name="data_usage_forground_label">Foreground:</string>
|
||||||
@@ -8655,6 +8657,27 @@
|
|||||||
<item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item>
|
<item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<!-- Data usage title text [CHAR LIMIT=30] -->
|
||||||
|
<string name="data_usage_title">Primary data</string>
|
||||||
|
|
||||||
|
<!-- Data usage string [CHAR LIMIT=30] -->
|
||||||
|
<string name="data_used"><xliff:g name="bytes" example="2 GB">^1</xliff:g> used</string>
|
||||||
|
|
||||||
|
<!-- Optional part of data usage showing the remaining amount [CHAR LIMIT=30] -->
|
||||||
|
<string name="data_remaining"><xliff:g name="bytes" example="2 GB">, ^1</xliff:g> left</string>
|
||||||
|
|
||||||
|
<!-- Informational text about time left in billing cycle [CHAR LIMIT=30] -->
|
||||||
|
<string name="cycle_left_time_text"><xliff:g name="time" example="2d">%1$s</xliff:g> left in this cycle</string>
|
||||||
|
|
||||||
|
<!-- Informational text about carrier and update time [CHAR LIMIT=30] -->
|
||||||
|
<string name="carrier_and_update_text">Updated by <xliff:g name="carrier" example="T-mobile">%1$s</xliff:g> <xliff:g name="time" example="3m">%2$s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- Informational text about update time only, without carrier [CHAR LIMIT=30] -->
|
||||||
|
<string name="no_carrier_update_text">Updated <xliff:g name="time" example="3m">%1$s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- Button to launch external data plan app [CHAR LIMIT=30] -->
|
||||||
|
<string name="launch_mdp_app_text">VIEW PLAN</string>
|
||||||
|
|
||||||
<!-- Name of Data Saver screens [CHAR LIMIT=30] -->
|
<!-- Name of Data Saver screens [CHAR LIMIT=30] -->
|
||||||
<string name="data_saver_title">Data saver</string>
|
<string name="data_saver_title">Data saver</string>
|
||||||
|
|
||||||
|
@@ -20,24 +20,8 @@
|
|||||||
android:key="data_usage_screen"
|
android:key="data_usage_screen"
|
||||||
android:title="@string/data_usage_summary_title">
|
android:title="@string/data_usage_summary_title">
|
||||||
|
|
||||||
<PreferenceCategory
|
<com.android.settings.datausage.DataUsageSummaryPreference
|
||||||
android:key="data_usage_category"
|
|
||||||
android:title="@string/usage">
|
|
||||||
|
|
||||||
<com.android.settings.SummaryPreference
|
|
||||||
android:key="status_header"
|
android:key="status_header"
|
||||||
android:selectable="false" />
|
android:selectable="false" />
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="limit_summary"
|
|
||||||
android:selectable="false"
|
|
||||||
settings:allowDividerBelow="true" />
|
|
||||||
|
|
||||||
<com.android.settings.datausage.DataSaverPreference
|
|
||||||
android:key="restrict_background"
|
|
||||||
android:title="@string/data_saver_title"
|
|
||||||
android:fragment="com.android.settings.datausage.DataSaverSummary" />
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@@ -18,7 +18,6 @@ import android.app.Activity;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.NetworkPolicyManager;
|
|
||||||
import android.net.NetworkTemplate;
|
import android.net.NetworkTemplate;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
@@ -28,6 +27,7 @@ import android.support.v7.preference.Preference;
|
|||||||
import android.support.v7.preference.PreferenceScreen;
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
import android.telephony.SubscriptionInfo;
|
import android.telephony.SubscriptionInfo;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.SubscriptionPlan;
|
||||||
import android.text.BidiFormatter;
|
import android.text.BidiFormatter;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
@@ -40,7 +40,6 @@ import android.view.MenuItem;
|
|||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SummaryPreference;
|
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.dashboard.SummaryLoader;
|
import com.android.settings.dashboard.SummaryLoader;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
@@ -65,7 +64,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
|
public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
|
||||||
|
|
||||||
private static final String KEY_STATUS_HEADER = "status_header";
|
private static final String KEY_STATUS_HEADER = "status_header";
|
||||||
private static final String KEY_LIMIT_SUMMARY = "limit_summary";
|
|
||||||
|
|
||||||
// Mobile data keys
|
// Mobile data keys
|
||||||
public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
|
public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
|
||||||
@@ -77,13 +75,9 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
|
public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
|
||||||
public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
|
public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
|
||||||
|
|
||||||
private DataUsageController mDataUsageController;
|
private DataUsageSummaryPreference mSummaryPreference;
|
||||||
private DataUsageInfoController mDataInfoController;
|
private DataUsageSummaryPreferenceController mSummaryController;
|
||||||
private SummaryPreference mSummaryPreference;
|
|
||||||
private Preference mLimitPreference;
|
|
||||||
private NetworkTemplate mDefaultTemplate;
|
private NetworkTemplate mDefaultTemplate;
|
||||||
private int mDataUsageTemplate;
|
|
||||||
private NetworkPolicyEditor mPolicyEditor;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHelpResource() {
|
public int getHelpResource() {
|
||||||
@@ -95,25 +89,20 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
|
|
||||||
mPolicyEditor = new NetworkPolicyEditor(policyManager);
|
|
||||||
|
|
||||||
boolean hasMobileData = DataUsageUtils.hasMobileData(context);
|
boolean hasMobileData = DataUsageUtils.hasMobileData(context);
|
||||||
mDataUsageController = new DataUsageController(context);
|
|
||||||
mDataInfoController = new DataUsageInfoController();
|
|
||||||
|
|
||||||
int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
|
int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
|
||||||
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||||
hasMobileData = false;
|
hasMobileData = false;
|
||||||
}
|
}
|
||||||
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
|
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
|
||||||
mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER);
|
mSummaryPreference = (DataUsageSummaryPreference) findPreference(KEY_STATUS_HEADER);
|
||||||
|
|
||||||
if (!hasMobileData || !isAdmin()) {
|
if (!hasMobileData || !isAdmin()) {
|
||||||
removePreference(KEY_RESTRICT_BACKGROUND);
|
removePreference(KEY_RESTRICT_BACKGROUND);
|
||||||
}
|
}
|
||||||
if (hasMobileData) {
|
if (hasMobileData) {
|
||||||
mLimitPreference = findPreference(KEY_LIMIT_SUMMARY);
|
|
||||||
List<SubscriptionInfo> subscriptions =
|
List<SubscriptionInfo> subscriptions =
|
||||||
services.mSubscriptionManager.getActiveSubscriptionInfoList();
|
services.mSubscriptionManager.getActiveSubscriptionInfoList();
|
||||||
if (subscriptions == null || subscriptions.size() == 0) {
|
if (subscriptions == null || subscriptions.size() == 0) {
|
||||||
@@ -127,10 +116,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
addMobileSection(subInfo.getSubscriptionId());
|
addMobileSection(subInfo.getSubscriptionId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mSummaryPreference.setSelectable(true);
|
|
||||||
} else {
|
|
||||||
removePreference(KEY_LIMIT_SUMMARY);
|
|
||||||
mSummaryPreference.setSelectable(false);
|
|
||||||
}
|
}
|
||||||
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
|
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
|
||||||
if (hasWifiRadio) {
|
if (hasWifiRadio) {
|
||||||
@@ -139,10 +124,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
if (hasEthernet(context)) {
|
if (hasEthernet(context)) {
|
||||||
addEthernetSection();
|
addEthernetSection();
|
||||||
}
|
}
|
||||||
mDataUsageTemplate = hasMobileData ? R.string.cell_data_template
|
|
||||||
: hasWifiRadio ? R.string.wifi_data_template
|
|
||||||
: R.string.ethernet_data_template;
|
|
||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +170,11 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
|
||||||
return null;
|
final ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
|
mSummaryController =
|
||||||
|
new DataUsageSummaryPreferenceController(context);
|
||||||
|
controllers.add(mSummaryController);
|
||||||
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMobileSection(int subId) {
|
private void addMobileSection(int subId) {
|
||||||
@@ -269,36 +254,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateState() {
|
private void updateState() {
|
||||||
DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
|
|
||||||
mDefaultTemplate);
|
|
||||||
Context context = getContext();
|
|
||||||
mDataInfoController.updateDataLimit(info,
|
|
||||||
services.mPolicyEditor.getPolicy(mDefaultTemplate));
|
|
||||||
|
|
||||||
if (mSummaryPreference != null) {
|
|
||||||
mSummaryPreference.setTitle(
|
|
||||||
formatUsage(context, getString(mDataUsageTemplate), info.usageLevel));
|
|
||||||
final long limit = mDataInfoController.getSummaryLimit(info);
|
|
||||||
mSummaryPreference.setSummary(info.period);
|
|
||||||
if (limit <= 0) {
|
|
||||||
mSummaryPreference.setChartEnabled(false);
|
|
||||||
} else {
|
|
||||||
mSummaryPreference.setChartEnabled(true);
|
|
||||||
mSummaryPreference.setLabels(Formatter.formatFileSize(context, 0),
|
|
||||||
Formatter.formatFileSize(context, limit));
|
|
||||||
mSummaryPreference.setRatios(info.usageLevel / (float) limit, 0,
|
|
||||||
(limit - info.usageLevel) / (float) limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) {
|
|
||||||
String warning = Formatter.formatFileSize(context, info.warningLevel);
|
|
||||||
String limit = Formatter.formatFileSize(context, info.limitLevel);
|
|
||||||
mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only
|
|
||||||
: R.string.cell_warning_and_limit, warning, limit));
|
|
||||||
} else if (mLimitPreference != null) {
|
|
||||||
mLimitPreference.setSummary(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferenceScreen screen = getPreferenceScreen();
|
PreferenceScreen screen = getPreferenceScreen();
|
||||||
for (int i = 1; i < screen.getPreferenceCount(); i++) {
|
for (int i = 1; i < screen.getPreferenceCount(); i++) {
|
||||||
((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
|
((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
|
||||||
@@ -323,6 +278,7 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
@Override
|
@Override
|
||||||
public void updateDataUsage() {
|
public void updateDataUsage() {
|
||||||
updateState();
|
updateState();
|
||||||
|
mSummaryController.updateState(mSummaryPreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SummaryProvider
|
private static class SummaryProvider
|
||||||
@@ -341,17 +297,39 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
|||||||
@Override
|
@Override
|
||||||
public void setListening(boolean listening) {
|
public void setListening(boolean listening) {
|
||||||
if (listening) {
|
if (listening) {
|
||||||
DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
|
|
||||||
String used;
|
|
||||||
if (info == null) {
|
|
||||||
used = Formatter.formatFileSize(mActivity, 0);
|
|
||||||
} else if (info.limitLevel <= 0) {
|
|
||||||
used = Formatter.formatFileSize(mActivity, info.usageLevel);
|
|
||||||
} else {
|
|
||||||
used = Utils.formatPercentage(info.usageLevel, info.limitLevel);
|
|
||||||
}
|
|
||||||
mSummaryLoader.setSummary(this,
|
mSummaryLoader.setSummary(this,
|
||||||
mActivity.getString(R.string.data_usage_summary_format, used));
|
mActivity.getString(R.string.data_usage_summary_format, formatUsedData()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatUsedData() {
|
||||||
|
SubscriptionManager subscriptionManager = (SubscriptionManager) mActivity
|
||||||
|
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
|
||||||
|
int defaultSubId = subscriptionManager.getDefaultSubscriptionId();
|
||||||
|
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||||
|
return formatFallbackData();
|
||||||
|
}
|
||||||
|
SubscriptionPlan dfltPlan = DataUsageSummaryPreferenceController
|
||||||
|
.getPrimaryPlan(subscriptionManager, defaultSubId);
|
||||||
|
if (dfltPlan == null) {
|
||||||
|
return formatFallbackData();
|
||||||
|
}
|
||||||
|
if (DataUsageSummaryPreferenceController.unlimited(dfltPlan.getDataLimitBytes())) {
|
||||||
|
return Formatter.formatFileSize(mActivity, dfltPlan.getDataUsageBytes());
|
||||||
|
} else {
|
||||||
|
return Utils.formatPercentage(dfltPlan.getDataUsageBytes(),
|
||||||
|
dfltPlan.getDataLimitBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatFallbackData() {
|
||||||
|
DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
|
||||||
|
if (info == null) {
|
||||||
|
return Formatter.formatFileSize(mActivity, 0);
|
||||||
|
} else if (info.limitLevel <= 0) {
|
||||||
|
return Formatter.formatFileSize(mActivity, info.usageLevel);
|
||||||
|
} else {
|
||||||
|
return Utils.formatPercentage(info.usageLevel, info.limitLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.datausage;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.v7.preference.PreferenceViewHolder;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SummaryPreference;
|
||||||
|
import com.android.settingslib.utils.StringUtil;
|
||||||
|
|
||||||
|
import libcore.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a summary of data usage.
|
||||||
|
*/
|
||||||
|
public class DataUsageSummaryPreference extends SummaryPreference {
|
||||||
|
|
||||||
|
private int mNumPlans;
|
||||||
|
/** The ending time of the billing cycle in milliseconds since epoch. */
|
||||||
|
private long mCycleEndTimeMs;
|
||||||
|
/** The time of the last update in standard milliseconds since the epoch */
|
||||||
|
private long mSnapshotTimeMs;
|
||||||
|
/** Name of carrier, or null if not available */
|
||||||
|
private CharSequence mCarrierName;
|
||||||
|
private String mLimitInfoText;
|
||||||
|
private Intent mLaunchIntent;
|
||||||
|
|
||||||
|
public DataUsageSummaryPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setLayoutResource(R.layout.data_usage_summary_preference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLimitInfo(String text) {
|
||||||
|
if (!Objects.equal(text, mLimitInfoText)) {
|
||||||
|
mLimitInfoText = text;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsageInfo(long cycleEnd, long snapshotTime, CharSequence carrierName,
|
||||||
|
int numPlans, Intent launchIntent) {
|
||||||
|
mCycleEndTimeMs = cycleEnd;
|
||||||
|
mSnapshotTimeMs = snapshotTime;
|
||||||
|
mCarrierName = carrierName;
|
||||||
|
mNumPlans = numPlans;
|
||||||
|
mLaunchIntent = launchIntent;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||||
|
super.onBindViewHolder(holder);
|
||||||
|
|
||||||
|
TextView usageTitle = (TextView) holder.findViewById(R.id.usage_title);
|
||||||
|
usageTitle.setVisibility(mNumPlans > 1 ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
|
||||||
|
cycleTime.setText(getContext().getString(R.string.cycle_left_time_text,
|
||||||
|
StringUtil.formatElapsedTime(getContext(),
|
||||||
|
mCycleEndTimeMs - System.currentTimeMillis(),false /* withSeconds */)));
|
||||||
|
|
||||||
|
TextView carrierInfo = (TextView) holder.findViewById(R.id.carrier_and_update);
|
||||||
|
setCarrierInfo(carrierInfo, mCarrierName, mSnapshotTimeMs);
|
||||||
|
|
||||||
|
Button launchButton = (Button) holder.findViewById(R.id.launch_mdp_app_button);
|
||||||
|
launchButton.setOnClickListener((view) -> {
|
||||||
|
getContext().sendBroadcast(mLaunchIntent);
|
||||||
|
});
|
||||||
|
if (mLaunchIntent != null) {
|
||||||
|
launchButton.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
launchButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
|
||||||
|
limitInfo.setVisibility(
|
||||||
|
mLimitInfoText == null || mLimitInfoText.isEmpty() ? View.GONE : View.VISIBLE);
|
||||||
|
limitInfo.setText(mLimitInfoText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCarrierInfo(TextView carrierInfo, CharSequence carrierName, long updateAge) {
|
||||||
|
if (mNumPlans > 0 && updateAge >= 0L) {
|
||||||
|
carrierInfo.setVisibility(View.VISIBLE);
|
||||||
|
if (carrierName != null) {
|
||||||
|
carrierInfo.setText(getContext().getString(R.string.carrier_and_update_text,
|
||||||
|
carrierName, StringUtil.formatRelativeTime(
|
||||||
|
getContext(), updateAge, false /* withSeconds */)));
|
||||||
|
} else {
|
||||||
|
carrierInfo.setText(getContext().getString(R.string.no_carrier_update_text,
|
||||||
|
StringUtil.formatRelativeTime(
|
||||||
|
getContext(), updateAge, false /* withSeconds */)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
carrierInfo.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.datausage;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.NetworkPolicyManager;
|
||||||
|
import android.net.NetworkTemplate;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
import android.telephony.SubscriptionInfo;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.telephony.SubscriptionPlan;
|
||||||
|
import android.text.BidiFormatter;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.text.format.Formatter;
|
||||||
|
import android.text.style.RelativeSizeSpan;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.RecurrenceRule;
|
||||||
|
|
||||||
|
import com.android.internal.util.CollectionUtils;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settingslib.NetworkPolicyEditor;
|
||||||
|
import com.android.settingslib.net.DataUsageController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the controller for the top of the data usage screen that retrieves carrier data from the
|
||||||
|
* new subscriptions framework API if available. The controller reads subscription information from
|
||||||
|
* the framework and falls back to legacy usage data if none are available.
|
||||||
|
*/
|
||||||
|
public class DataUsageSummaryPreferenceController extends BasePreferenceController {
|
||||||
|
|
||||||
|
private static final String TAG = "DataUsageController";
|
||||||
|
private static final String KEY = "status_header";
|
||||||
|
private static final long PETA = 1000000000000000L;
|
||||||
|
private static final float RELATIVE_SIZE_LARGE = 1.25f * 1.25f; // (1/0.8)^2
|
||||||
|
private static final float RELATIVE_SIZE_SMALL = 1.0f / RELATIVE_SIZE_LARGE; // 0.8^2
|
||||||
|
|
||||||
|
private final DataUsageController mDataUsageController;
|
||||||
|
private final DataUsageInfoController mDataInfoController;
|
||||||
|
private final NetworkTemplate mDefaultTemplate;
|
||||||
|
private final NetworkPolicyEditor mPolicyEditor;
|
||||||
|
private final int mDataUsageTemplate;
|
||||||
|
private final boolean mHasMobileData;
|
||||||
|
private final SubscriptionManager mSubscriptionManager;
|
||||||
|
|
||||||
|
/** Name of the carrier, or null if not available */
|
||||||
|
private CharSequence mCarrierName;
|
||||||
|
|
||||||
|
/** The number of registered plans, [0,N] */
|
||||||
|
private int mDataplanCount;
|
||||||
|
|
||||||
|
/** The time of the last update in milliseconds since the epoch, or -1 if unknown */
|
||||||
|
private long mSnapshotTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the first registered plan if one exists or the size of the warning if it is set.
|
||||||
|
* -1 if no information is available.
|
||||||
|
*/
|
||||||
|
private long mDataplanSize;
|
||||||
|
/** The number of bytes used since the start of the cycle. */
|
||||||
|
private long mDataplanUse;
|
||||||
|
/** The starting time of the billing cycle in ms since the epoch */
|
||||||
|
private long mCycleStart;
|
||||||
|
/** The ending time of the billing cycle in ms since the epoch */
|
||||||
|
private long mCycleEnd;
|
||||||
|
|
||||||
|
private Intent mManageSubscriptionIntent;
|
||||||
|
|
||||||
|
public DataUsageSummaryPreferenceController(Context context) {
|
||||||
|
super(context, KEY);
|
||||||
|
|
||||||
|
final int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
|
||||||
|
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
|
||||||
|
NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
|
||||||
|
mPolicyEditor = new NetworkPolicyEditor(policyManager);
|
||||||
|
|
||||||
|
mHasMobileData = DataUsageUtils.hasMobileData(context)
|
||||||
|
&& defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||||
|
|
||||||
|
mDataUsageController = new DataUsageController(context);
|
||||||
|
mDataInfoController = new DataUsageInfoController();
|
||||||
|
|
||||||
|
if (mHasMobileData) {
|
||||||
|
mDataUsageTemplate = R.string.cell_data_template;
|
||||||
|
} else if (DataUsageUtils.hasWifiRadio(context)) {
|
||||||
|
mDataUsageTemplate = R.string.wifi_data_template;
|
||||||
|
} else {
|
||||||
|
mDataUsageTemplate = R.string.ethernet_data_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSubscriptionManager = (SubscriptionManager)
|
||||||
|
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
DataUsageSummaryPreferenceController(
|
||||||
|
Context context,
|
||||||
|
DataUsageController dataUsageController,
|
||||||
|
DataUsageInfoController dataInfoController,
|
||||||
|
NetworkTemplate defaultTemplate,
|
||||||
|
NetworkPolicyEditor policyEditor,
|
||||||
|
int dataUsageTemplate,
|
||||||
|
boolean hasMobileData,
|
||||||
|
SubscriptionManager subscriptionManager) {
|
||||||
|
super(context, KEY);
|
||||||
|
mDataUsageController = dataUsageController;
|
||||||
|
mDataInfoController = dataInfoController;
|
||||||
|
mDefaultTemplate = defaultTemplate;
|
||||||
|
mPolicyEditor = policyEditor;
|
||||||
|
mDataUsageTemplate = dataUsageTemplate;
|
||||||
|
mHasMobileData = hasMobileData;
|
||||||
|
mSubscriptionManager = subscriptionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setPlanValues(int dataPlanCount, long dataPlanSize, long dataPlanUse) {
|
||||||
|
mDataplanCount = dataPlanCount;
|
||||||
|
mDataplanSize = dataPlanSize;
|
||||||
|
mDataplanUse = dataPlanUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setCarrierValues(String carrierName, long snapshotTime, long cycleEnd, Intent intent) {
|
||||||
|
mCarrierName = carrierName;
|
||||||
|
mSnapshotTime = snapshotTime;
|
||||||
|
mCycleEnd = cycleEnd;
|
||||||
|
mManageSubscriptionIntent = intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
DataUsageSummaryPreference summaryPreference = (DataUsageSummaryPreference) preference;
|
||||||
|
DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
|
||||||
|
mDefaultTemplate);
|
||||||
|
|
||||||
|
mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
|
||||||
|
|
||||||
|
if (mSubscriptionManager != null) {
|
||||||
|
refreshDataplanInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDataplanCount == 0 && (info.warningLevel > 0 || info.limitLevel > 0)) {
|
||||||
|
final String warning = Formatter.formatFileSize(mContext, info.warningLevel);
|
||||||
|
final String limit = Formatter.formatFileSize(mContext, info.limitLevel);
|
||||||
|
summaryPreference.setLimitInfo(mContext.getString(info.limitLevel <= 0
|
||||||
|
? R.string.cell_warning_only
|
||||||
|
: R.string.cell_warning_and_limit, warning, limit));
|
||||||
|
} else {
|
||||||
|
summaryPreference.setLimitInfo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder title = new StringBuilder();
|
||||||
|
if (mHasMobileData) {
|
||||||
|
title.append(formatUsage(mContext, mContext.getString(R.string.data_used),
|
||||||
|
mDataplanUse));
|
||||||
|
if (mDataplanCount >= 0 && mDataplanSize > 0L) {
|
||||||
|
title.append(formatUsage(mContext, mContext.getString(R.string.data_remaining),
|
||||||
|
mDataplanSize - mDataplanUse));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
title.append(formatUsage(mContext, mContext.getString(mDataUsageTemplate),
|
||||||
|
mDataplanUse));
|
||||||
|
}
|
||||||
|
summaryPreference.setTitle(title.toString());
|
||||||
|
|
||||||
|
if (mDataplanSize <= 0) {
|
||||||
|
summaryPreference.setChartEnabled(false);
|
||||||
|
} else {
|
||||||
|
summaryPreference.setChartEnabled(true);
|
||||||
|
summaryPreference.setLabels(Formatter.formatFileSize(mContext, 0 /* sizeBytes */),
|
||||||
|
Formatter.formatFileSize(mContext, mDataplanSize));
|
||||||
|
summaryPreference.setRatios(mDataplanUse / (float) mDataplanSize, 0 /* middle */,
|
||||||
|
(mDataplanSize - mDataplanUse) / (float) mDataplanSize);
|
||||||
|
}
|
||||||
|
summaryPreference.setUsageInfo(mCycleEnd, mSnapshotTime, mCarrierName,
|
||||||
|
mDataplanCount, mManageSubscriptionIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/70950124) add test for this method once the robolectric shadow run script is
|
||||||
|
// completed (b/3526807)
|
||||||
|
private void refreshDataplanInfo(DataUsageController.DataUsageInfo info) {
|
||||||
|
// reset data before overwriting
|
||||||
|
mCarrierName = null;
|
||||||
|
mDataplanCount = 0;
|
||||||
|
mDataplanSize = mDataInfoController.getSummaryLimit(info);
|
||||||
|
mDataplanUse = info.usageLevel;
|
||||||
|
mCycleStart = info.cycleStart;
|
||||||
|
mCycleEnd = info.cycleEnd;
|
||||||
|
mSnapshotTime = -1L;
|
||||||
|
|
||||||
|
final int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
|
||||||
|
final SubscriptionInfo subInfo = mSubscriptionManager.getDefaultDataSubscriptionInfo();
|
||||||
|
if (subInfo != null && mHasMobileData) {
|
||||||
|
mCarrierName = subInfo.getCarrierName();
|
||||||
|
List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(defaultSubId);
|
||||||
|
final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, defaultSubId);
|
||||||
|
if (primaryPlan != null) {
|
||||||
|
mDataplanCount = plans.size();
|
||||||
|
mDataplanSize = primaryPlan.getDataLimitBytes();
|
||||||
|
if (unlimited(mDataplanSize)) {
|
||||||
|
mDataplanSize = 0L;
|
||||||
|
}
|
||||||
|
mDataplanUse = primaryPlan.getDataUsageBytes();
|
||||||
|
|
||||||
|
RecurrenceRule rule = primaryPlan.getCycleRule();
|
||||||
|
if (rule != null && rule.start != null && rule.end != null) {
|
||||||
|
mCycleStart = rule.start.toEpochSecond() * 1000L;
|
||||||
|
mCycleEnd = rule.end.toEpochSecond() * 1000L;
|
||||||
|
}
|
||||||
|
mSnapshotTime = System.currentTimeMillis() - primaryPlan.getDataUsageTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mManageSubscriptionIntent =
|
||||||
|
mSubscriptionManager.createManageSubscriptionIntent(defaultSubId);
|
||||||
|
Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + defaultSubId
|
||||||
|
+ ", intent " + mManageSubscriptionIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SubscriptionPlan getPrimaryPlan(SubscriptionManager subManager, int primaryId) {
|
||||||
|
List<SubscriptionPlan> plans = subManager.getSubscriptionPlans(primaryId);
|
||||||
|
if (CollectionUtils.isEmpty(plans)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// First plan in the list is the primary plan
|
||||||
|
SubscriptionPlan plan = plans.get(0);
|
||||||
|
return plan.getDataLimitBytes() > 0
|
||||||
|
&& saneSize(plan.getDataUsageBytes())
|
||||||
|
&& plan.getCycleRule() != null ? plan : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean saneSize(long value) {
|
||||||
|
return value >= 0L && value < PETA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean unlimited(long size) {
|
||||||
|
return size == SubscriptionPlan.BYTES_UNLIMITED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
private static CharSequence formatUsage(Context context, String template, long usageLevel) {
|
||||||
|
final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
|
||||||
|
|
||||||
|
final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
|
||||||
|
usageLevel, Formatter.FLAG_CALCULATE_ROUNDED);
|
||||||
|
final SpannableString enlargedValue = new SpannableString(usedResult.value);
|
||||||
|
enlargedValue.setSpan(
|
||||||
|
new RelativeSizeSpan(RELATIVE_SIZE_LARGE), 0, enlargedValue.length(), FLAGS);
|
||||||
|
|
||||||
|
final SpannableString amountTemplate = new SpannableString(
|
||||||
|
context.getString(com.android.internal.R.string.fileSizeSuffix)
|
||||||
|
.replace("%1$s", "^1").replace("%2$s", "^2"));
|
||||||
|
final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate,
|
||||||
|
enlargedValue, usedResult.units);
|
||||||
|
|
||||||
|
final SpannableString fullTemplate = new SpannableString(template);
|
||||||
|
fullTemplate.setSpan(
|
||||||
|
new RelativeSizeSpan(RELATIVE_SIZE_SMALL), 0, fullTemplate.length(), FLAGS);
|
||||||
|
return TextUtils.expandTemplate(fullTemplate,
|
||||||
|
BidiFormatter.getInstance().unicodeWrap(formattedUsage.toString()));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.datausage;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.NetworkTemplate;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settingslib.NetworkPolicyEditor;
|
||||||
|
import com.android.settingslib.net.DataUsageController;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class DataUsageSummaryPreferenceControllerTest {
|
||||||
|
private static final long UPDATE_BACKOFF_MS = TimeUnit.MINUTES.toMillis(13);
|
||||||
|
private static final long CYCLE_BACKOFF_MS = TimeUnit.DAYS.toMillis(6);
|
||||||
|
private static final long CYCLE_LENGTH_MS = TimeUnit.DAYS.toMillis(30);
|
||||||
|
private static final long USAGE1 = 373000000L;
|
||||||
|
private static final long LIMIT1 = 1000000000L;
|
||||||
|
private static final String CARRIER_NAME = "z-mobile";
|
||||||
|
private static final String PERIOD = "Feb";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataUsageController mDataUsageController;
|
||||||
|
@Mock
|
||||||
|
private DataUsageInfoController mDataInfoController;
|
||||||
|
@Mock
|
||||||
|
private DataUsageSummaryPreference mSummaryPreference;
|
||||||
|
@Mock
|
||||||
|
private NetworkPolicyEditor mPolicyEditor;
|
||||||
|
@Mock
|
||||||
|
private NetworkTemplate mNetworkTemplate;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private DataUsageSummaryPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
|
mController = new DataUsageSummaryPreferenceController(
|
||||||
|
mContext,
|
||||||
|
mDataUsageController,
|
||||||
|
mDataInfoController,
|
||||||
|
mNetworkTemplate,
|
||||||
|
mPolicyEditor,
|
||||||
|
R.string.cell_data_template,
|
||||||
|
true,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSummaryUpdate_onePlan_basic() {
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
|
||||||
|
|
||||||
|
final Intent intent = new Intent();
|
||||||
|
|
||||||
|
when(mDataUsageController.getDataUsageInfo()).thenReturn(info);
|
||||||
|
mController.setPlanValues(1 /* dataPlanCount */, LIMIT1, USAGE1);
|
||||||
|
mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
|
||||||
|
|
||||||
|
mController.updateState(mSummaryPreference);
|
||||||
|
verify(mSummaryPreference).setLimitInfo(null);
|
||||||
|
verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
|
||||||
|
CARRIER_NAME, 1 /* numPlans */, intent);
|
||||||
|
verify(mSummaryPreference).setChartEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSummaryUpdate_noPlan_basic() {
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
|
||||||
|
|
||||||
|
final Intent intent = new Intent();
|
||||||
|
|
||||||
|
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
|
||||||
|
mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
|
||||||
|
mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
|
||||||
|
|
||||||
|
mController.updateState(mSummaryPreference);
|
||||||
|
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
|
||||||
|
verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
|
||||||
|
CARRIER_NAME, 0 /* numPlans */, intent);
|
||||||
|
verify(mSummaryPreference).setChartEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSummaryUpdate_noCarrier_basic() {
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
|
||||||
|
|
||||||
|
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
|
||||||
|
mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
|
||||||
|
mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
|
||||||
|
info.cycleEnd, null /* intent */);
|
||||||
|
mController.updateState(mSummaryPreference);
|
||||||
|
|
||||||
|
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
|
||||||
|
verify(mSummaryPreference).setUsageInfo(
|
||||||
|
info.cycleEnd,
|
||||||
|
-1L /* snapshotTime */,
|
||||||
|
null /* carrierName */,
|
||||||
|
0 /* numPlans */,
|
||||||
|
null /* launchIntent */);
|
||||||
|
verify(mSummaryPreference).setChartEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSummaryUpdate_noPlanData_basic() {
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
|
||||||
|
|
||||||
|
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
|
||||||
|
mController.setPlanValues(0 /* dataPlanCount */, -1L /* dataPlanSize */, USAGE1);
|
||||||
|
mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
|
||||||
|
info.cycleEnd, null /* intent */);
|
||||||
|
mController.updateState(mSummaryPreference);
|
||||||
|
|
||||||
|
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
|
||||||
|
verify(mSummaryPreference).setUsageInfo(
|
||||||
|
info.cycleEnd,
|
||||||
|
-1L /* snapshotTime */,
|
||||||
|
null /* carrierName */,
|
||||||
|
0 /* numPlans */,
|
||||||
|
null /* launchIntent */);
|
||||||
|
verify(mSummaryPreference).setChartEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataUsageController.DataUsageInfo createTestDataUsageInfo(long now) {
|
||||||
|
DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo();
|
||||||
|
info.carrier = CARRIER_NAME;
|
||||||
|
info.period = PERIOD;
|
||||||
|
info.startDate = now;
|
||||||
|
info.limitLevel = LIMIT1;
|
||||||
|
info.warningLevel = LIMIT1 >> 1;
|
||||||
|
info.usageLevel = USAGE1;
|
||||||
|
info.cycleStart = now - CYCLE_BACKOFF_MS;
|
||||||
|
info.cycleEnd = info.cycleStart + CYCLE_LENGTH_MS;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.datausage;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.v7.preference.PreferenceViewHolder;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
|
||||||
|
import com.android.settingslib.utils.StringUtil;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows =
|
||||||
|
SettingsShadowResourcesImpl.class)
|
||||||
|
public class DataUsageSummaryPreferenceTest {
|
||||||
|
private static final long CYCLE_DURATION_MILLIS = 1000000000L;
|
||||||
|
private static final long UPDATE_LAG_MILLIS = 10000000L;
|
||||||
|
private static final String DUMMY_CARRIER = "z-mobile";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private PreferenceViewHolder mHolder;
|
||||||
|
private DataUsageSummaryPreference mSummaryPreference;
|
||||||
|
private TextView mUsageTitle;
|
||||||
|
private TextView mCycleTime;
|
||||||
|
private TextView mCarrierInfo;
|
||||||
|
private TextView mDataLimits;
|
||||||
|
private Button mLaunchButton;
|
||||||
|
|
||||||
|
private long mCycleEnd;
|
||||||
|
private long mUpdateTime;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
mSummaryPreference = new DataUsageSummaryPreference(mContext, null /* attrs */);
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
|
View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
|
||||||
|
false /* attachToRoot */);
|
||||||
|
|
||||||
|
mHolder = PreferenceViewHolder.createInstanceForTests(view);
|
||||||
|
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
mCycleEnd = now + CYCLE_DURATION_MILLIS;
|
||||||
|
mUpdateTime = now - UPDATE_LAG_MILLIS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withLaunchIntent_launchButtonShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mLaunchButton.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withoutLaunchIntent_launchButtonNotShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
|
||||||
|
null /* launchIntent */);
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mLaunchButton.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withDataPlans_carrierInfoShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 1 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withNoDataPlans_carrierInfoNotShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withNoDataPlans_usageTitleNotShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mUsageTitle.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_withMultipleDataPlans_usageTitleShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 2 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mUsageTitle.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUsageInfo_cycleRemainingTimeShown() {
|
||||||
|
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
|
||||||
|
new Intent());
|
||||||
|
String cyclePrefix = StringUtil.formatElapsedTime(mContext, CYCLE_DURATION_MILLIS,
|
||||||
|
false /* withSeconds */).toString();
|
||||||
|
String text = mContext.getString(R.string.cycle_left_time_text, cyclePrefix);
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mCycleTime.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mCycleTime.getText()).isEqualTo(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLimitInfo_withLimitInfo_dataLimitsShown() {
|
||||||
|
final String limitText = "test limit text";
|
||||||
|
mSummaryPreference.setLimitInfo(limitText);
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mDataLimits.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
|
assertThat(mDataLimits.getText()).isEqualTo(limitText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetLimitInfo_withNullLimitInfo_dataLimitsNotShown() {
|
||||||
|
mSummaryPreference.setLimitInfo(null);
|
||||||
|
|
||||||
|
bindViewHolder();
|
||||||
|
assertThat(mDataLimits.getVisibility()).isEqualTo(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindViewHolder() {
|
||||||
|
mSummaryPreference.onBindViewHolder(mHolder);
|
||||||
|
mUsageTitle = (TextView) mHolder.findViewById(R.id.usage_title);
|
||||||
|
mCycleTime = (TextView) mHolder.findViewById(R.id.cycle_left_time);
|
||||||
|
mCarrierInfo = (TextView) mHolder.findViewById(R.id.carrier_and_update);
|
||||||
|
mDataLimits = (TextView) mHolder.findViewById(R.id.data_limits);
|
||||||
|
mLaunchButton = (Button) mHolder.findViewById(R.id.launch_mdp_app_button);
|
||||||
|
}
|
||||||
|
}
|
@@ -137,7 +137,6 @@ public class BaseSearchIndexProviderTest {
|
|||||||
final List<String> nonIndexableKeys = provider
|
final List<String> nonIndexableKeys = provider
|
||||||
.getNonIndexableKeys(RuntimeEnvironment.application);
|
.getNonIndexableKeys(RuntimeEnvironment.application);
|
||||||
|
|
||||||
assertThat(nonIndexableKeys).containsAllOf("status_header", "limit_summary",
|
assertThat(nonIndexableKeys).contains("status_header");
|
||||||
"restrict_background");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user