Merge "Expose SubscriptionPlan API." into oc-mr1-dev
am: 84c6684bba
Change-Id: I9e05d8ae075c698bc4c19132df92ea8f3f3fc52b
This commit is contained in:
@@ -39536,7 +39536,7 @@ package android.telephony {
|
||||
method public android.os.PersistableBundle getConfigForSubId(int);
|
||||
method public void notifyConfigChangedForSubId(int);
|
||||
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
|
||||
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final deprecated int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
|
||||
@@ -39578,9 +39578,10 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
|
||||
field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
|
||||
field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
|
||||
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
|
||||
field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
|
||||
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
|
||||
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
|
||||
@@ -39637,7 +39638,7 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
|
||||
field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
|
||||
field public static final java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final deprecated java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
|
||||
field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
|
||||
field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
|
||||
@@ -40149,8 +40150,10 @@ package android.telephony {
|
||||
method public static int getDefaultSmsSubscriptionId();
|
||||
method public static int getDefaultSubscriptionId();
|
||||
method public static int getDefaultVoiceSubscriptionId();
|
||||
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
|
||||
method public boolean isNetworkRoaming(int);
|
||||
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
|
||||
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
|
||||
field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
|
||||
field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
|
||||
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
|
||||
@@ -40164,6 +40167,38 @@ package android.telephony {
|
||||
method public void onSubscriptionsChanged();
|
||||
}
|
||||
|
||||
public final class SubscriptionPlan implements android.os.Parcelable {
|
||||
method public java.util.Iterator<android.util.Pair<java.time.ZonedDateTime, java.time.ZonedDateTime>> cycleIterator();
|
||||
method public int describeContents();
|
||||
method public int getDataLimitBehavior();
|
||||
method public long getDataLimitBytes();
|
||||
method public long getDataUsageBytes();
|
||||
method public long getDataUsageTime();
|
||||
method public java.lang.CharSequence getSummary();
|
||||
method public java.lang.CharSequence getTitle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL
|
||||
field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionPlan> CREATOR;
|
||||
field public static final int LIMIT_BEHAVIOR_BILLED = 1; // 0x1
|
||||
field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0
|
||||
field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2
|
||||
field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff
|
||||
field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
}
|
||||
|
||||
public static class SubscriptionPlan.Builder {
|
||||
method public android.telephony.SubscriptionPlan build();
|
||||
method public static android.telephony.SubscriptionPlan.Builder createNonrecurring(java.time.ZonedDateTime, java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
|
||||
method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence);
|
||||
method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence);
|
||||
}
|
||||
|
||||
public class TelephonyManager {
|
||||
method public boolean canChangeDtmfToneLength();
|
||||
method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
|
||||
|
||||
@@ -146,7 +146,6 @@ package android {
|
||||
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
|
||||
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
|
||||
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
|
||||
field public static final java.lang.String MANAGE_FALLBACK_SUBSCRIPTION_PLANS = "android.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS";
|
||||
field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
|
||||
field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
|
||||
field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
|
||||
@@ -43083,7 +43082,7 @@ package android.telephony {
|
||||
method public void notifyConfigChangedForSubId(int);
|
||||
method public void updateConfigForPhoneId(int, java.lang.String);
|
||||
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
|
||||
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final deprecated int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
|
||||
@@ -43125,9 +43124,10 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
|
||||
field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
|
||||
field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
|
||||
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
|
||||
field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
|
||||
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
|
||||
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
|
||||
@@ -43184,7 +43184,7 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
|
||||
field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
|
||||
field public static final java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final deprecated java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
|
||||
field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
|
||||
field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
|
||||
@@ -43698,8 +43698,10 @@ package android.telephony {
|
||||
method public static int getDefaultSmsSubscriptionId();
|
||||
method public static int getDefaultSubscriptionId();
|
||||
method public static int getDefaultVoiceSubscriptionId();
|
||||
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
|
||||
method public boolean isNetworkRoaming(int);
|
||||
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
|
||||
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
|
||||
field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
|
||||
field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
|
||||
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
|
||||
@@ -43713,6 +43715,38 @@ package android.telephony {
|
||||
method public void onSubscriptionsChanged();
|
||||
}
|
||||
|
||||
public final class SubscriptionPlan implements android.os.Parcelable {
|
||||
method public java.util.Iterator<android.util.Pair<java.time.ZonedDateTime, java.time.ZonedDateTime>> cycleIterator();
|
||||
method public int describeContents();
|
||||
method public int getDataLimitBehavior();
|
||||
method public long getDataLimitBytes();
|
||||
method public long getDataUsageBytes();
|
||||
method public long getDataUsageTime();
|
||||
method public java.lang.CharSequence getSummary();
|
||||
method public java.lang.CharSequence getTitle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL
|
||||
field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionPlan> CREATOR;
|
||||
field public static final int LIMIT_BEHAVIOR_BILLED = 1; // 0x1
|
||||
field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0
|
||||
field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2
|
||||
field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff
|
||||
field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
}
|
||||
|
||||
public static class SubscriptionPlan.Builder {
|
||||
method public android.telephony.SubscriptionPlan build();
|
||||
method public static android.telephony.SubscriptionPlan.Builder createNonrecurring(java.time.ZonedDateTime, java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
|
||||
method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence);
|
||||
method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence);
|
||||
}
|
||||
|
||||
public final class TelephonyHistogram implements android.os.Parcelable {
|
||||
ctor public TelephonyHistogram(int, int, int);
|
||||
ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
|
||||
|
||||
@@ -39762,7 +39762,7 @@ package android.telephony {
|
||||
method public android.os.PersistableBundle getConfigForSubId(int);
|
||||
method public void notifyConfigChangedForSubId(int);
|
||||
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
|
||||
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final deprecated int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
|
||||
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
|
||||
field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
|
||||
@@ -39804,9 +39804,10 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
|
||||
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
|
||||
field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
|
||||
field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
|
||||
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
|
||||
field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
|
||||
field public static final deprecated java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
|
||||
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
|
||||
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
|
||||
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
|
||||
@@ -39863,7 +39864,7 @@ package android.telephony {
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
|
||||
field public static final java.lang.String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
|
||||
field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
|
||||
field public static final java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final deprecated java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
|
||||
field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
|
||||
field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
|
||||
field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
|
||||
@@ -40375,8 +40376,10 @@ package android.telephony {
|
||||
method public static int getDefaultSmsSubscriptionId();
|
||||
method public static int getDefaultSubscriptionId();
|
||||
method public static int getDefaultVoiceSubscriptionId();
|
||||
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
|
||||
method public boolean isNetworkRoaming(int);
|
||||
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
|
||||
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
|
||||
field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
|
||||
field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
|
||||
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
|
||||
@@ -40390,6 +40393,38 @@ package android.telephony {
|
||||
method public void onSubscriptionsChanged();
|
||||
}
|
||||
|
||||
public final class SubscriptionPlan implements android.os.Parcelable {
|
||||
method public java.util.Iterator<android.util.Pair<java.time.ZonedDateTime, java.time.ZonedDateTime>> cycleIterator();
|
||||
method public int describeContents();
|
||||
method public int getDataLimitBehavior();
|
||||
method public long getDataLimitBytes();
|
||||
method public long getDataUsageBytes();
|
||||
method public long getDataUsageTime();
|
||||
method public java.lang.CharSequence getSummary();
|
||||
method public java.lang.CharSequence getTitle();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL
|
||||
field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionPlan> CREATOR;
|
||||
field public static final int LIMIT_BEHAVIOR_BILLED = 1; // 0x1
|
||||
field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0
|
||||
field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2
|
||||
field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff
|
||||
field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
|
||||
}
|
||||
|
||||
public static class SubscriptionPlan.Builder {
|
||||
method public android.telephony.SubscriptionPlan build();
|
||||
method public static android.telephony.SubscriptionPlan.Builder createNonrecurring(java.time.ZonedDateTime, java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
|
||||
method public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
|
||||
method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
|
||||
method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence);
|
||||
method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence);
|
||||
}
|
||||
|
||||
public class TelephonyManager {
|
||||
method public boolean canChangeDtmfToneLength();
|
||||
method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
|
||||
|
||||
@@ -71,7 +71,5 @@ interface INetworkPolicyManager {
|
||||
SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
|
||||
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
|
||||
|
||||
String getSubscriptionPlanOwner(int subId);
|
||||
|
||||
void factoryReset(String subscriber);
|
||||
}
|
||||
|
||||
@@ -16,16 +16,21 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.BackupUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.RecurrenceRule;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -35,10 +40,8 @@ import java.util.Objects;
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
/**
|
||||
* Current Version of the Backup Serializer.
|
||||
*/
|
||||
private static final int BACKUP_VERSION = 1;
|
||||
private static final int VERSION_INIT = 1;
|
||||
private static final int VERSION_RULE = 2;
|
||||
|
||||
public static final int CYCLE_NONE = -1;
|
||||
public static final long WARNING_DISABLED = -1;
|
||||
@@ -46,8 +49,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
public static final long SNOOZE_NEVER = -1;
|
||||
|
||||
public NetworkTemplate template;
|
||||
@Deprecated public int cycleDay = CYCLE_NONE;
|
||||
@Deprecated public String cycleTimezone = "UTC";
|
||||
public RecurrenceRule cycleRule;
|
||||
public long warningBytes = WARNING_DISABLED;
|
||||
public long limitBytes = LIMIT_DISABLED;
|
||||
public long lastWarningSnooze = SNOOZE_NEVER;
|
||||
@@ -57,7 +59,12 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
|
||||
private static final long DEFAULT_MTU = 1500;
|
||||
|
||||
public NetworkPolicy() {
|
||||
public static RecurrenceRule buildRule(int cycleDay, ZoneId cycleTimezone) {
|
||||
if (cycleDay != NetworkPolicy.CYCLE_NONE) {
|
||||
return RecurrenceRule.buildRecurringMonthly(cycleDay, cycleTimezone);
|
||||
} else {
|
||||
return RecurrenceRule.buildNever();
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -67,12 +74,19 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
SNOOZE_NEVER, metered, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
|
||||
long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze,
|
||||
boolean metered, boolean inferred) {
|
||||
this.template = checkNotNull(template, "missing NetworkTemplate");
|
||||
this.cycleDay = cycleDay;
|
||||
this.cycleTimezone = checkNotNull(cycleTimezone, "missing cycleTimezone");
|
||||
this(template, buildRule(cycleDay, ZoneId.of(cycleTimezone)), warningBytes,
|
||||
limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred);
|
||||
}
|
||||
|
||||
public NetworkPolicy(NetworkTemplate template, RecurrenceRule cycleRule, long warningBytes,
|
||||
long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered,
|
||||
boolean inferred) {
|
||||
this.template = Preconditions.checkNotNull(template, "missing NetworkTemplate");
|
||||
this.cycleRule = Preconditions.checkNotNull(cycleRule, "missing RecurrenceRule");
|
||||
this.warningBytes = warningBytes;
|
||||
this.limitBytes = limitBytes;
|
||||
this.lastWarningSnooze = lastWarningSnooze;
|
||||
@@ -81,23 +95,21 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
this.inferred = inferred;
|
||||
}
|
||||
|
||||
public NetworkPolicy(Parcel in) {
|
||||
template = in.readParcelable(null);
|
||||
cycleDay = in.readInt();
|
||||
cycleTimezone = in.readString();
|
||||
warningBytes = in.readLong();
|
||||
limitBytes = in.readLong();
|
||||
lastWarningSnooze = in.readLong();
|
||||
lastLimitSnooze = in.readLong();
|
||||
metered = in.readInt() != 0;
|
||||
inferred = in.readInt() != 0;
|
||||
private NetworkPolicy(Parcel source) {
|
||||
template = source.readParcelable(null);
|
||||
cycleRule = source.readParcelable(null);
|
||||
warningBytes = source.readLong();
|
||||
limitBytes = source.readLong();
|
||||
lastWarningSnooze = source.readLong();
|
||||
lastLimitSnooze = source.readLong();
|
||||
metered = source.readInt() != 0;
|
||||
inferred = source.readInt() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(template, flags);
|
||||
dest.writeInt(cycleDay);
|
||||
dest.writeString(cycleTimezone);
|
||||
dest.writeParcelable(cycleRule, flags);
|
||||
dest.writeLong(warningBytes);
|
||||
dest.writeLong(limitBytes);
|
||||
dest.writeLong(lastWarningSnooze);
|
||||
@@ -111,6 +123,10 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
|
||||
return cycleRule.cycleIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if given measurement is over {@link #warningBytes}.
|
||||
*/
|
||||
@@ -141,7 +157,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
* Test if this policy has a cycle defined, after which usage should reset.
|
||||
*/
|
||||
public boolean hasCycle() {
|
||||
return cycleDay != CYCLE_NONE;
|
||||
return cycleRule.cycleIterator().hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,7 +175,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
|
||||
return Objects.hash(template, cycleRule, warningBytes, limitBytes,
|
||||
lastWarningSnooze, lastLimitSnooze, metered, inferred);
|
||||
}
|
||||
|
||||
@@ -167,30 +183,29 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof NetworkPolicy) {
|
||||
final NetworkPolicy other = (NetworkPolicy) obj;
|
||||
return cycleDay == other.cycleDay && warningBytes == other.warningBytes
|
||||
return warningBytes == other.warningBytes
|
||||
&& limitBytes == other.limitBytes
|
||||
&& lastWarningSnooze == other.lastWarningSnooze
|
||||
&& lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
|
||||
&& inferred == other.inferred
|
||||
&& Objects.equals(cycleTimezone, other.cycleTimezone)
|
||||
&& Objects.equals(template, other.template);
|
||||
&& Objects.equals(template, other.template)
|
||||
&& Objects.equals(cycleRule, other.cycleRule);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder("NetworkPolicy");
|
||||
builder.append("[").append(template).append("]:");
|
||||
builder.append(" cycleDay=").append(cycleDay);
|
||||
builder.append(", cycleTimezone=").append(cycleTimezone);
|
||||
builder.append(", warningBytes=").append(warningBytes);
|
||||
builder.append(", limitBytes=").append(limitBytes);
|
||||
builder.append(", lastWarningSnooze=").append(lastWarningSnooze);
|
||||
builder.append(", lastLimitSnooze=").append(lastLimitSnooze);
|
||||
builder.append(", metered=").append(metered);
|
||||
builder.append(", inferred=").append(inferred);
|
||||
return builder.toString();
|
||||
return new StringBuilder("NetworkPolicy{")
|
||||
.append("template=").append(template)
|
||||
.append(" cycleRule=").append(cycleRule)
|
||||
.append(" warningBytes=").append(warningBytes)
|
||||
.append(" limitBytes=").append(limitBytes)
|
||||
.append(" lastWarningSnooze=").append(lastWarningSnooze)
|
||||
.append(" lastLimitSnooze=").append(lastLimitSnooze)
|
||||
.append(" metered=").append(metered)
|
||||
.append(" inferred=").append(inferred)
|
||||
.append("}").toString();
|
||||
}
|
||||
|
||||
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
|
||||
@@ -209,10 +224,9 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
|
||||
out.writeInt(BACKUP_VERSION);
|
||||
out.writeInt(VERSION_RULE);
|
||||
out.write(template.getBytesForBackup());
|
||||
out.writeInt(cycleDay);
|
||||
BackupUtils.writeString(out, cycleTimezone);
|
||||
cycleRule.writeToStream(out);
|
||||
out.writeLong(warningBytes);
|
||||
out.writeLong(limitBytes);
|
||||
out.writeLong(lastWarningSnooze);
|
||||
@@ -224,21 +238,36 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
|
||||
|
||||
public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
|
||||
BackupUtils.BadVersionException {
|
||||
int version = in.readInt();
|
||||
if (version < 1 || version > BACKUP_VERSION) {
|
||||
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
|
||||
final int version = in.readInt();
|
||||
switch (version) {
|
||||
case VERSION_INIT: {
|
||||
NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
|
||||
int cycleDay = in.readInt();
|
||||
String cycleTimeZone = BackupUtils.readString(in);
|
||||
long warningBytes = in.readLong();
|
||||
long limitBytes = in.readLong();
|
||||
long lastWarningSnooze = in.readLong();
|
||||
long lastLimitSnooze = in.readLong();
|
||||
boolean metered = in.readInt() == 1;
|
||||
boolean inferred = in.readInt() == 1;
|
||||
return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes,
|
||||
limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred);
|
||||
}
|
||||
case VERSION_RULE: {
|
||||
NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
|
||||
RecurrenceRule cycleRule = new RecurrenceRule(in);
|
||||
long warningBytes = in.readLong();
|
||||
long limitBytes = in.readLong();
|
||||
long lastWarningSnooze = in.readLong();
|
||||
long lastLimitSnooze = in.readLong();
|
||||
boolean metered = in.readInt() == 1;
|
||||
boolean inferred = in.readInt() == 1;
|
||||
return new NetworkPolicy(template, cycleRule, warningBytes,
|
||||
limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred);
|
||||
}
|
||||
default: {
|
||||
throw new BackupUtils.BadVersionException("Unknown backup version: " + version);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
|
||||
int cycleDay = in.readInt();
|
||||
String cycleTimeZone = BackupUtils.readString(in);
|
||||
long warningBytes = in.readLong();
|
||||
long limitBytes = in.readLong();
|
||||
long lastWarningSnooze = in.readLong();
|
||||
long lastLimitSnooze = in.readLong();
|
||||
boolean metered = in.readInt() == 1;
|
||||
boolean inferred = in.readInt() == 1;
|
||||
return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
|
||||
lastWarningSnooze, lastLimitSnooze, metered, inferred);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public class NetworkPolicyManager {
|
||||
|
||||
/** {@hide} */
|
||||
public static Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator(NetworkPolicy policy) {
|
||||
return SubscriptionPlan.convert(policy).cycleIterator();
|
||||
return policy.cycleIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
257
core/java/android/util/RecurrenceRule.java
Normal file
257
core/java/android/util/RecurrenceRule.java
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.util;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Description of an event that should recur over time at a specific interval
|
||||
* between two anchor points in time.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class RecurrenceRule implements Parcelable {
|
||||
private static final String TAG = "RecurrenceRule";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static final int VERSION_INIT = 0;
|
||||
|
||||
/** {@hide} */
|
||||
@VisibleForTesting
|
||||
public static Clock sClock = Clock.systemDefaultZone();
|
||||
|
||||
public final ZonedDateTime start;
|
||||
public final ZonedDateTime end;
|
||||
public final Period period;
|
||||
|
||||
public RecurrenceRule(ZonedDateTime start, ZonedDateTime end, Period period) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static RecurrenceRule buildNever() {
|
||||
return new RecurrenceRule(null, null, null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static RecurrenceRule buildRecurringMonthly(int dayOfMonth, ZoneId zone) {
|
||||
// Assume we started last January, since it has all possible days
|
||||
final ZonedDateTime now = ZonedDateTime.now(sClock).withZoneSameInstant(zone);
|
||||
final ZonedDateTime start = ZonedDateTime.of(
|
||||
now.toLocalDate().minusYears(1).withMonth(1).withDayOfMonth(dayOfMonth),
|
||||
LocalTime.MIDNIGHT, zone);
|
||||
return new RecurrenceRule(start, null, Period.ofMonths(1));
|
||||
}
|
||||
|
||||
private RecurrenceRule(Parcel source) {
|
||||
start = convertZonedDateTime(source.readString());
|
||||
end = convertZonedDateTime(source.readString());
|
||||
period = convertPeriod(source.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(convertZonedDateTime(start));
|
||||
dest.writeString(convertZonedDateTime(end));
|
||||
dest.writeString(convertPeriod(period));
|
||||
}
|
||||
|
||||
public RecurrenceRule(DataInputStream in) throws IOException {
|
||||
final int version = in.readInt();
|
||||
switch (version) {
|
||||
case VERSION_INIT:
|
||||
start = convertZonedDateTime(BackupUtils.readString(in));
|
||||
end = convertZonedDateTime(BackupUtils.readString(in));
|
||||
period = convertPeriod(BackupUtils.readString(in));
|
||||
default:
|
||||
throw new ProtocolException("Unknown version " + version);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
out.writeInt(VERSION_INIT);
|
||||
BackupUtils.writeString(out, convertZonedDateTime(start));
|
||||
BackupUtils.writeString(out, convertZonedDateTime(end));
|
||||
BackupUtils.writeString(out, convertPeriod(period));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("RecurrenceRule{")
|
||||
.append("start=").append(start)
|
||||
.append(" end=").append(end)
|
||||
.append(" period=").append(period)
|
||||
.append("}").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(start, end, period);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof RecurrenceRule) {
|
||||
final RecurrenceRule other = (RecurrenceRule) obj;
|
||||
return Objects.equals(start, other.start)
|
||||
&& Objects.equals(end, other.end)
|
||||
&& Objects.equals(period, other.period);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<RecurrenceRule> CREATOR = new Parcelable.Creator<RecurrenceRule>() {
|
||||
@Override
|
||||
public RecurrenceRule createFromParcel(Parcel source) {
|
||||
return new RecurrenceRule(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecurrenceRule[] newArray(int size) {
|
||||
return new RecurrenceRule[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Deprecated
|
||||
public boolean isMonthly() {
|
||||
return start != null
|
||||
&& period != null
|
||||
&& period.getYears() == 0
|
||||
&& period.getMonths() == 1
|
||||
&& period.getDays() == 0;
|
||||
}
|
||||
|
||||
public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
|
||||
if (period != null) {
|
||||
return new RecurringIterator();
|
||||
} else {
|
||||
return new NonrecurringIterator();
|
||||
}
|
||||
}
|
||||
|
||||
private class NonrecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
|
||||
boolean hasNext;
|
||||
|
||||
public NonrecurringIterator() {
|
||||
hasNext = (start != null) && (end != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<ZonedDateTime, ZonedDateTime> next() {
|
||||
hasNext = false;
|
||||
return new Pair<>(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
private class RecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
|
||||
int i;
|
||||
ZonedDateTime cycleStart;
|
||||
ZonedDateTime cycleEnd;
|
||||
|
||||
public RecurringIterator() {
|
||||
final ZonedDateTime anchor = (end != null) ? end
|
||||
: ZonedDateTime.now(sClock).withZoneSameInstant(start.getZone());
|
||||
if (DEBUG) Log.d(TAG, "Resolving using anchor " + anchor);
|
||||
|
||||
updateCycle();
|
||||
|
||||
// Walk forwards until we find first cycle after now
|
||||
while (anchor.toEpochSecond() > cycleEnd.toEpochSecond()) {
|
||||
i++;
|
||||
updateCycle();
|
||||
}
|
||||
|
||||
// Walk backwards until we find first cycle before now
|
||||
while (anchor.toEpochSecond() <= cycleStart.toEpochSecond()) {
|
||||
i--;
|
||||
updateCycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCycle() {
|
||||
cycleStart = roundBoundaryTime(start.plus(period.multipliedBy(i)));
|
||||
cycleEnd = roundBoundaryTime(start.plus(period.multipliedBy(i + 1)));
|
||||
}
|
||||
|
||||
private ZonedDateTime roundBoundaryTime(ZonedDateTime boundary) {
|
||||
if (isMonthly() && (boundary.getDayOfMonth() < start.getDayOfMonth())) {
|
||||
// When forced to end a monthly cycle early, we want to count
|
||||
// that entire day against the boundary.
|
||||
return ZonedDateTime.of(boundary.toLocalDate(), LocalTime.MAX, start.getZone());
|
||||
} else {
|
||||
return boundary;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return cycleStart.toEpochSecond() >= start.toEpochSecond();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<ZonedDateTime, ZonedDateTime> next() {
|
||||
if (DEBUG) Log.d(TAG, "Cycle " + i + " from " + cycleStart + " to " + cycleEnd);
|
||||
Pair<ZonedDateTime, ZonedDateTime> p = new Pair<>(cycleStart, cycleEnd);
|
||||
i--;
|
||||
updateCycle();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertZonedDateTime(ZonedDateTime time) {
|
||||
return time != null ? time.toString() : null;
|
||||
}
|
||||
|
||||
public static ZonedDateTime convertZonedDateTime(String time) {
|
||||
return time != null ? ZonedDateTime.parse(time) : null;
|
||||
}
|
||||
|
||||
public static String convertPeriod(Period period) {
|
||||
return period != null ? period.toString() : null;
|
||||
}
|
||||
|
||||
public static Period convertPeriod(String period) {
|
||||
return period != null ? Period.parse(period) : null;
|
||||
}
|
||||
}
|
||||
@@ -1694,10 +1694,10 @@ public class XmlUtils {
|
||||
return in.getAttributeValue(null, name);
|
||||
}
|
||||
|
||||
public static void writeStringAttribute(XmlSerializer out, String name, String value)
|
||||
public static void writeStringAttribute(XmlSerializer out, String name, CharSequence value)
|
||||
throws IOException {
|
||||
if (value != null) {
|
||||
out.attribute(null, name, value);
|
||||
out.attribute(null, name, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3156,12 +3156,6 @@
|
||||
<permission android:name="android.permission.MANAGE_NETWORK_POLICY"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows an application to manage fallback subscription plans.
|
||||
Note that another app providing plans for an explicit HNI will always
|
||||
take precidence over these fallback plans. @hide -->
|
||||
<permission android:name="android.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- @SystemApi @hide @deprecated use UPDATE_DEVICE_STATS instead -->
|
||||
<permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
146
core/tests/coretests/src/android/util/RecurrenceRuleTest.java
Normal file
146
core/tests/coretests/src/android/util/RecurrenceRuleTest.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.util;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Iterator;
|
||||
|
||||
@SmallTest
|
||||
public class RecurrenceRuleTest extends TestCase {
|
||||
|
||||
static Clock sOriginalClock;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
sOriginalClock = RecurrenceRule.sClock;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
RecurrenceRule.sClock = sOriginalClock;
|
||||
}
|
||||
|
||||
private void setClock(Instant instant) {
|
||||
RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
public void testSimpleMonth() throws Exception {
|
||||
setClock(Instant.parse("2015-11-20T10:15:30.00Z"));
|
||||
final RecurrenceRule r = new RecurrenceRule(
|
||||
ZonedDateTime.parse("2010-11-14T00:00:00.000Z"),
|
||||
null,
|
||||
Period.ofMonths(1));
|
||||
|
||||
assertTrue(r.isMonthly());
|
||||
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = r.cycleIterator();
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(Pair.create(
|
||||
ZonedDateTime.parse("2015-11-14T00:00:00.00Z"),
|
||||
ZonedDateTime.parse("2015-12-14T00:00:00.00Z")), it.next());
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(Pair.create(
|
||||
ZonedDateTime.parse("2015-10-14T00:00:00.00Z"),
|
||||
ZonedDateTime.parse("2015-11-14T00:00:00.00Z")), it.next());
|
||||
}
|
||||
|
||||
public void testSimpleDays() throws Exception {
|
||||
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
|
||||
final RecurrenceRule r = new RecurrenceRule(
|
||||
ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
|
||||
ZonedDateTime.parse("2010-11-20T00:11:00.000Z"),
|
||||
Period.ofDays(3));
|
||||
|
||||
assertFalse(r.isMonthly());
|
||||
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = r.cycleIterator();
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(Pair.create(
|
||||
ZonedDateTime.parse("2010-11-17T00:11:00.00Z"),
|
||||
ZonedDateTime.parse("2010-11-20T00:11:00.00Z")), it.next());
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(Pair.create(
|
||||
ZonedDateTime.parse("2010-11-14T00:11:00.00Z"),
|
||||
ZonedDateTime.parse("2010-11-17T00:11:00.00Z")), it.next());
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
public void testNotRecurring() throws Exception {
|
||||
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
|
||||
final RecurrenceRule r = new RecurrenceRule(
|
||||
ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
|
||||
ZonedDateTime.parse("2010-11-20T00:11:00.000Z"),
|
||||
null);
|
||||
|
||||
assertFalse(r.isMonthly());
|
||||
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = r.cycleIterator();
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(Pair.create(
|
||||
ZonedDateTime.parse("2010-11-14T00:11:00.000Z"),
|
||||
ZonedDateTime.parse("2010-11-20T00:11:00.000Z")), it.next());
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
public void testNever() throws Exception {
|
||||
setClock(Instant.parse("2015-01-01T10:15:30.00Z"));
|
||||
final RecurrenceRule r = RecurrenceRule.buildNever();
|
||||
|
||||
assertFalse(r.isMonthly());
|
||||
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = r.cycleIterator();
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
public void testSane() throws Exception {
|
||||
final RecurrenceRule r = new RecurrenceRule(
|
||||
ZonedDateTime.parse("1980-01-31T00:00:00.000Z"),
|
||||
ZonedDateTime.parse("2030-01-31T00:00:00.000Z"),
|
||||
Period.ofMonths(1));
|
||||
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = r.cycleIterator();
|
||||
ZonedDateTime lastStart = null;
|
||||
int months = 0;
|
||||
while (it.hasNext()) {
|
||||
final Pair<ZonedDateTime, ZonedDateTime> cycle = it.next();
|
||||
|
||||
// Make sure cycle has reasonable length
|
||||
final long length = cycle.second.toEpochSecond() - cycle.first.toEpochSecond();
|
||||
assertTrue(cycle + " must be more than 4 weeks", length >= 2419200);
|
||||
assertTrue(cycle + " must be less than 5 weeks", length <= 3024000);
|
||||
|
||||
// Make sure we have no gaps
|
||||
if (lastStart != null) {
|
||||
assertEquals(lastStart, cycle.second);
|
||||
}
|
||||
lastStart = cycle.first;
|
||||
months++;
|
||||
}
|
||||
|
||||
assertEquals(600, months);
|
||||
}
|
||||
}
|
||||
@@ -30,10 +30,12 @@ import android.net.NetworkTemplate;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.Time;
|
||||
import android.util.RecurrenceRule;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -129,35 +131,36 @@ public class NetworkPolicyEditor {
|
||||
@Deprecated
|
||||
private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
|
||||
// TODO: move this into framework to share with NetworkPolicyManagerService
|
||||
final int cycleDay;
|
||||
final String cycleTimezone;
|
||||
final RecurrenceRule cycleRule;
|
||||
final boolean metered;
|
||||
|
||||
if (template.getMatchRule() == MATCH_WIFI) {
|
||||
cycleDay = CYCLE_NONE;
|
||||
cycleTimezone = Time.TIMEZONE_UTC;
|
||||
cycleRule = RecurrenceRule.buildNever();
|
||||
metered = false;
|
||||
} else {
|
||||
final Time time = new Time();
|
||||
time.setToNow();
|
||||
cycleDay = time.monthDay;
|
||||
cycleTimezone = time.timezone;
|
||||
cycleRule = RecurrenceRule.buildRecurringMonthly(ZonedDateTime.now().getDayOfMonth(),
|
||||
ZoneId.systemDefault());
|
||||
metered = true;
|
||||
}
|
||||
|
||||
return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
|
||||
return new NetworkPolicy(template, cycleRule, WARNING_DISABLED,
|
||||
LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getPolicyCycleDay(NetworkTemplate template) {
|
||||
final NetworkPolicy policy = getPolicy(template);
|
||||
return (policy != null) ? policy.cycleDay : CYCLE_NONE;
|
||||
if (policy != null && policy.cycleRule.isMonthly()) {
|
||||
return policy.cycleRule.start.getDayOfMonth();
|
||||
} else {
|
||||
return CYCLE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
|
||||
final NetworkPolicy policy = getOrCreatePolicy(template);
|
||||
policy.cycleDay = cycleDay;
|
||||
policy.cycleTimezone = cycleTimezone;
|
||||
policy.cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.of(cycleTimezone));
|
||||
policy.inferred = false;
|
||||
policy.clearSnooze();
|
||||
writeAsync();
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.server.net;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
|
||||
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
||||
import static android.Manifest.permission.MANAGE_FALLBACK_SUBSCRIPTION_PLANS;
|
||||
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
|
||||
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
|
||||
import static android.Manifest.permission.READ_PHONE_STATE;
|
||||
@@ -28,7 +27,6 @@ import static android.content.Intent.ACTION_UID_REMOVED;
|
||||
import static android.content.Intent.ACTION_USER_ADDED;
|
||||
import static android.content.Intent.ACTION_USER_REMOVED;
|
||||
import static android.content.Intent.EXTRA_UID;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
|
||||
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
|
||||
@@ -76,9 +74,11 @@ import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
|
||||
import static com.android.internal.util.XmlUtils.readIntAttribute;
|
||||
import static com.android.internal.util.XmlUtils.readLongAttribute;
|
||||
import static com.android.internal.util.XmlUtils.readStringAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeIntAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeLongAttribute;
|
||||
import static com.android.internal.util.XmlUtils.writeStringAttribute;
|
||||
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
|
||||
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
|
||||
|
||||
@@ -157,14 +157,15 @@ import android.telephony.SubscriptionPlan;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.Formatter;
|
||||
import android.text.format.Time;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.NtpTrustedTime;
|
||||
import android.util.Pair;
|
||||
import android.util.RecurrenceRule;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.TrustedTime;
|
||||
@@ -180,6 +181,7 @@ import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.DeviceIdleController;
|
||||
import com.android.server.EventLogTags;
|
||||
import com.android.server.LocalServices;
|
||||
@@ -192,7 +194,6 @@ import libcore.io.IoUtils;
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.File;
|
||||
@@ -205,6 +206,7 @@ import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -257,7 +259,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private static final int VERSION_SWITCH_APP_ID = 8;
|
||||
private static final int VERSION_ADDED_NETWORK_ID = 9;
|
||||
private static final int VERSION_SWITCH_UID = 10;
|
||||
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
|
||||
private static final int VERSION_ADDED_CYCLE = 11;
|
||||
private static final int VERSION_LATEST = VERSION_ADDED_CYCLE;
|
||||
|
||||
/**
|
||||
* Max items written to {@link #ProcStateSeqHistory}.
|
||||
@@ -275,6 +278,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
private static final String TAG_POLICY_LIST = "policy-list";
|
||||
private static final String TAG_NETWORK_POLICY = "network-policy";
|
||||
private static final String TAG_SUBSCRIPTION_PLAN = "subscription-plan";
|
||||
private static final String TAG_UID_POLICY = "uid-policy";
|
||||
private static final String TAG_APP_POLICY = "app-policy";
|
||||
private static final String TAG_WHITELIST = "whitelist";
|
||||
@@ -286,8 +290,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
|
||||
private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
|
||||
private static final String ATTR_NETWORK_ID = "networkId";
|
||||
private static final String ATTR_CYCLE_DAY = "cycleDay";
|
||||
private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone";
|
||||
@Deprecated private static final String ATTR_CYCLE_DAY = "cycleDay";
|
||||
@Deprecated private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone";
|
||||
private static final String ATTR_CYCLE_START = "cycleStart";
|
||||
private static final String ATTR_CYCLE_END = "cycleEnd";
|
||||
private static final String ATTR_CYCLE_PERIOD = "cyclePeriod";
|
||||
private static final String ATTR_WARNING_BYTES = "warningBytes";
|
||||
private static final String ATTR_LIMIT_BYTES = "limitBytes";
|
||||
private static final String ATTR_LAST_SNOOZE = "lastSnooze";
|
||||
@@ -298,6 +305,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private static final String ATTR_UID = "uid";
|
||||
private static final String ATTR_APP_ID = "appId";
|
||||
private static final String ATTR_POLICY = "policy";
|
||||
private static final String ATTR_SUB_ID = "subId";
|
||||
private static final String ATTR_TITLE = "title";
|
||||
private static final String ATTR_SUMMARY = "summary";
|
||||
private static final String ATTR_LIMIT_BEHAVIOR = "limitBehavior";
|
||||
private static final String ATTR_USAGE_BYTES = "usageBytes";
|
||||
private static final String ATTR_USAGE_TIME = "usageTime";
|
||||
|
||||
private static final String ACTION_ALLOW_BACKGROUND =
|
||||
"com.android.server.net.action.ALLOW_BACKGROUND";
|
||||
@@ -359,6 +372,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
/** Currently active network rules for ifaces. */
|
||||
final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>();
|
||||
|
||||
/** Defined subscription plans. */
|
||||
final SparseArray<SubscriptionPlan[]> mSubscriptionPlans = new SparseArray<>();
|
||||
|
||||
/** Defined UID policies. */
|
||||
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
|
||||
/** Currently derived rules for each UID. */
|
||||
@@ -998,7 +1014,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
// cycle boundary to recompute notifications.
|
||||
|
||||
// examine stats for each active policy
|
||||
final long currentTime = currentTimeMillis();
|
||||
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
|
||||
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
|
||||
// ignore policies that aren't relevant to user
|
||||
@@ -1273,20 +1288,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int cycleDay = getCycleDayFromCarrierConfig(config, policy.cycleDay);
|
||||
final int currentCycleDay;
|
||||
if (policy.cycleRule.isMonthly()) {
|
||||
currentCycleDay = policy.cycleRule.start.getDayOfMonth();
|
||||
} else {
|
||||
currentCycleDay = NetworkPolicy.CYCLE_NONE;
|
||||
}
|
||||
|
||||
final int cycleDay = getCycleDayFromCarrierConfig(config, currentCycleDay);
|
||||
final long warningBytes = getWarningBytesFromCarrierConfig(config,
|
||||
policy.warningBytes);
|
||||
final long limitBytes = getLimitBytesFromCarrierConfig(config,
|
||||
policy.limitBytes);
|
||||
|
||||
if (policy.cycleDay == cycleDay &&
|
||||
if (currentCycleDay == cycleDay &&
|
||||
policy.warningBytes == warningBytes &&
|
||||
policy.limitBytes == limitBytes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
policyUpdated = true;
|
||||
policy.cycleDay = cycleDay;
|
||||
policy.cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.systemDefault());
|
||||
policy.warningBytes = warningBytes;
|
||||
policy.limitBytes = limitBytes;
|
||||
|
||||
@@ -1456,7 +1478,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
// TODO: reset any policy-disabled networks when any policy is removed
|
||||
// completely, which is currently rare case.
|
||||
|
||||
final long currentTime = currentTimeMillis();
|
||||
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
|
||||
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
|
||||
// shortcut when policy has no limit
|
||||
@@ -1573,7 +1594,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
// apply each policy that we found ifaces for; compute remaining data
|
||||
// based on current cycle and historical stats, and push to kernel.
|
||||
final long currentTime = currentTimeMillis();
|
||||
for (int i = mNetworkRules.size()-1; i >= 0; i--) {
|
||||
final NetworkPolicy policy = mNetworkRules.keyAt(i);
|
||||
final String[] ifaces = mNetworkRules.valueAt(i);
|
||||
@@ -1721,20 +1741,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
public NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) {
|
||||
PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
|
||||
|
||||
// assume usage cycle starts today
|
||||
final Time time = new Time();
|
||||
time.setToNow();
|
||||
|
||||
final String cycleTimezone = time.timezone;
|
||||
|
||||
final int cycleDay = getCycleDayFromCarrierConfig(config, time.monthDay);
|
||||
final int cycleDay = getCycleDayFromCarrierConfig(config,
|
||||
ZonedDateTime.now().getDayOfMonth());
|
||||
final long warningBytes = getWarningBytesFromCarrierConfig(config,
|
||||
getPlatformDefaultWarningBytes());
|
||||
final long limitBytes = getLimitBytesFromCarrierConfig(config,
|
||||
getPlatformDefaultLimitBytes());
|
||||
|
||||
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
|
||||
final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
|
||||
final RecurrenceRule cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.systemDefault());
|
||||
final NetworkPolicy policy = new NetworkPolicy(template, cycleRule,
|
||||
warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
|
||||
return policy;
|
||||
}
|
||||
@@ -1744,6 +1760,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
|
||||
// clear any existing policy and read from disk
|
||||
mNetworkPolicy.clear();
|
||||
mSubscriptionPlans.clear();
|
||||
mUidPolicy.clear();
|
||||
|
||||
FileInputStream fis = null;
|
||||
@@ -1787,12 +1804,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
} else {
|
||||
networkId = null;
|
||||
}
|
||||
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
|
||||
final String cycleTimezone;
|
||||
if (version >= VERSION_ADDED_TIMEZONE) {
|
||||
cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE);
|
||||
final RecurrenceRule cycleRule;
|
||||
if (version >= VERSION_ADDED_CYCLE) {
|
||||
final String start = readStringAttribute(in, ATTR_CYCLE_START);
|
||||
final String end = readStringAttribute(in, ATTR_CYCLE_END);
|
||||
final String period = readStringAttribute(in, ATTR_CYCLE_PERIOD);
|
||||
cycleRule = new RecurrenceRule(
|
||||
RecurrenceRule.convertZonedDateTime(start),
|
||||
RecurrenceRule.convertZonedDateTime(end),
|
||||
RecurrenceRule.convertPeriod(period));
|
||||
} else {
|
||||
cycleTimezone = Time.TIMEZONE_UTC;
|
||||
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
|
||||
final String cycleTimezone;
|
||||
if (version >= VERSION_ADDED_TIMEZONE) {
|
||||
cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE);
|
||||
} else {
|
||||
cycleTimezone = "UTC";
|
||||
}
|
||||
cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.of(cycleTimezone));
|
||||
}
|
||||
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
|
||||
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
|
||||
@@ -1834,10 +1863,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
final NetworkTemplate template = new NetworkTemplate(networkTemplate,
|
||||
subscriberId, networkId);
|
||||
if (template.isPersistable()) {
|
||||
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
|
||||
cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
|
||||
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
|
||||
warningBytes, limitBytes, lastWarningSnooze,
|
||||
lastLimitSnooze, metered, inferred));
|
||||
}
|
||||
|
||||
} else if (TAG_SUBSCRIPTION_PLAN.equals(tag)) {
|
||||
final String start = readStringAttribute(in, ATTR_CYCLE_START);
|
||||
final String end = readStringAttribute(in, ATTR_CYCLE_END);
|
||||
final String period = readStringAttribute(in, ATTR_CYCLE_PERIOD);
|
||||
final SubscriptionPlan.Builder builder = new SubscriptionPlan.Builder(
|
||||
RecurrenceRule.convertZonedDateTime(start),
|
||||
RecurrenceRule.convertZonedDateTime(end),
|
||||
RecurrenceRule.convertPeriod(period));
|
||||
builder.setTitle(readStringAttribute(in, ATTR_TITLE));
|
||||
builder.setSummary(readStringAttribute(in, ATTR_SUMMARY));
|
||||
|
||||
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES,
|
||||
SubscriptionPlan.BYTES_UNKNOWN);
|
||||
final int limitBehavior = readIntAttribute(in, ATTR_LIMIT_BEHAVIOR,
|
||||
SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN);
|
||||
if (limitBytes != SubscriptionPlan.BYTES_UNKNOWN
|
||||
&& limitBehavior != SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
|
||||
builder.setDataLimit(limitBytes, limitBehavior);
|
||||
}
|
||||
|
||||
final long usageBytes = readLongAttribute(in, ATTR_USAGE_BYTES,
|
||||
SubscriptionPlan.BYTES_UNKNOWN);
|
||||
final long usageTime = readLongAttribute(in, ATTR_USAGE_TIME,
|
||||
SubscriptionPlan.TIME_UNKNOWN);
|
||||
if (usageBytes != SubscriptionPlan.BYTES_UNKNOWN
|
||||
&& usageTime != SubscriptionPlan.TIME_UNKNOWN) {
|
||||
builder.setDataUsage(usageBytes, usageTime);
|
||||
}
|
||||
|
||||
final int subId = readIntAttribute(in, ATTR_SUB_ID);
|
||||
final SubscriptionPlan plan = builder.build();
|
||||
mSubscriptionPlans.put(subId, ArrayUtils.appendElement(
|
||||
SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
|
||||
|
||||
} else if (TAG_UID_POLICY.equals(tag)) {
|
||||
final int uid = readIntAttribute(in, ATTR_UID);
|
||||
final int policy = readIntAttribute(in, ATTR_POLICY);
|
||||
@@ -1898,9 +1962,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
} catch (FileNotFoundException e) {
|
||||
// missing policy is okay, probably first boot
|
||||
upgradeDefaultBackgroundDataUL();
|
||||
} catch (IOException e) {
|
||||
Log.wtf(TAG, "problem reading network policy", e);
|
||||
} catch (XmlPullParserException e) {
|
||||
} catch (Exception e) {
|
||||
Log.wtf(TAG, "problem reading network policy", e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(fis);
|
||||
@@ -1994,8 +2056,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
if (networkId != null) {
|
||||
out.attribute(null, ATTR_NETWORK_ID, networkId);
|
||||
}
|
||||
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
|
||||
out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone);
|
||||
writeStringAttribute(out, ATTR_CYCLE_START,
|
||||
RecurrenceRule.convertZonedDateTime(policy.cycleRule.start));
|
||||
writeStringAttribute(out, ATTR_CYCLE_END,
|
||||
RecurrenceRule.convertZonedDateTime(policy.cycleRule.end));
|
||||
writeStringAttribute(out, ATTR_CYCLE_PERIOD,
|
||||
RecurrenceRule.convertPeriod(policy.cycleRule.period));
|
||||
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
|
||||
writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
|
||||
writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
|
||||
@@ -2005,6 +2071,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
out.endTag(null, TAG_NETWORK_POLICY);
|
||||
}
|
||||
|
||||
// write all known subscription plans
|
||||
for (int i = 0; i < mSubscriptionPlans.size(); i++) {
|
||||
final int subId = mSubscriptionPlans.keyAt(i);
|
||||
final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i);
|
||||
if (ArrayUtils.isEmpty(plans)) continue;
|
||||
|
||||
for (SubscriptionPlan plan : plans) {
|
||||
out.startTag(null, TAG_SUBSCRIPTION_PLAN);
|
||||
writeIntAttribute(out, ATTR_SUB_ID, subId);
|
||||
final RecurrenceRule cycleRule = plan.getCycleRule();
|
||||
writeStringAttribute(out, ATTR_CYCLE_START,
|
||||
RecurrenceRule.convertZonedDateTime(cycleRule.start));
|
||||
writeStringAttribute(out, ATTR_CYCLE_END,
|
||||
RecurrenceRule.convertZonedDateTime(cycleRule.end));
|
||||
writeStringAttribute(out, ATTR_CYCLE_PERIOD,
|
||||
RecurrenceRule.convertPeriod(cycleRule.period));
|
||||
writeStringAttribute(out, ATTR_TITLE, plan.getTitle());
|
||||
writeStringAttribute(out, ATTR_SUMMARY, plan.getSummary());
|
||||
writeLongAttribute(out, ATTR_LIMIT_BYTES, plan.getDataLimitBytes());
|
||||
writeIntAttribute(out, ATTR_LIMIT_BEHAVIOR, plan.getDataLimitBehavior());
|
||||
writeLongAttribute(out, ATTR_USAGE_BYTES, plan.getDataUsageBytes());
|
||||
writeLongAttribute(out, ATTR_USAGE_TIME, plan.getDataUsageTime());
|
||||
out.endTag(null, TAG_SUBSCRIPTION_PLAN);
|
||||
}
|
||||
}
|
||||
|
||||
// write all known uid policies
|
||||
for (int i = 0; i < mUidPolicy.size(); i++) {
|
||||
final int uid = mUidPolicy.keyAt(i);
|
||||
@@ -2506,27 +2598,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
}
|
||||
|
||||
final SubscriptionInfo si;
|
||||
final PersistableBundle config;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
si = mContext.getSystemService(SubscriptionManager.class)
|
||||
.getActiveSubscriptionInfo(subId);
|
||||
config = mCarrierConfigManager.getConfigForSubId(subId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
// First check: does caller have carrier access?
|
||||
// First check: is caller the CarrierService?
|
||||
if (si.isEmbedded() && si.canManageSubscription(mContext, callingPackage)) {
|
||||
Slog.v(TAG, "Granting access because " + callingPackage + " is carrier");
|
||||
return;
|
||||
}
|
||||
|
||||
// Second check: was caller first to claim this HNI?
|
||||
// TODO: extend to support external data sources
|
||||
// Second check: has the CarrierService delegated access?
|
||||
if (config != null) {
|
||||
final String overridePackage = config
|
||||
.getString(CarrierConfigManager.KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING, null);
|
||||
if (!TextUtils.isEmpty(overridePackage)
|
||||
&& Objects.equals(overridePackage, callingPackage)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Final check: does caller have fallback permission?
|
||||
if (mContext.checkCallingOrSelfPermission(
|
||||
MANAGE_FALLBACK_SUBSCRIPTION_PLANS) == PERMISSION_GRANTED) {
|
||||
Slog.v(TAG, "Granting access because " + callingPackage + " is fallback");
|
||||
// Third check: is caller the fallback/default CarrierService?
|
||||
final String defaultPackage = mCarrierConfigManager.getDefaultCarrierServicePackageName();
|
||||
if (!TextUtils.isEmpty(defaultPackage)
|
||||
&& Objects.equals(defaultPackage, callingPackage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2538,11 +2638,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) {
|
||||
enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
|
||||
|
||||
// TODO: extend to support external data sources
|
||||
if (!"com.android.settings".equals(callingPackage)) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
final String fake = SystemProperties.get("fw.fake_plan");
|
||||
if (!TextUtils.isEmpty(fake)) {
|
||||
final List<SubscriptionPlan> plans = new ArrayList<>();
|
||||
@@ -2550,7 +2645,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
plans.add(SubscriptionPlan.Builder
|
||||
.createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
|
||||
.setTitle("G-Mobile")
|
||||
.setDataWarning(2 * TrafficStats.GB_IN_BYTES)
|
||||
.setDataLimit(5 * TrafficStats.GB_IN_BYTES,
|
||||
SubscriptionPlan.LIMIT_BEHAVIOR_BILLED)
|
||||
.setDataUsage(1 * TrafficStats.GB_IN_BYTES,
|
||||
@@ -2562,7 +2656,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
.setTitle("G-Mobile is the carriers name who this plan belongs to")
|
||||
.setSummary("Crazy unlimited bandwidth plan with incredibly long title "
|
||||
+ "that should be cut off to prevent UI from looking terrible")
|
||||
.setDataWarning(2 * TrafficStats.GB_IN_BYTES)
|
||||
.setDataLimit(5 * TrafficStats.GB_IN_BYTES,
|
||||
SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
|
||||
.setDataUsage(1 * TrafficStats.GB_IN_BYTES,
|
||||
@@ -2615,19 +2708,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
return plans.toArray(new SubscriptionPlan[plans.size()]);
|
||||
}
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
|
||||
final NetworkTemplate template = NetworkTemplate
|
||||
.buildTemplateMobileAll(tm.getSubscriberId(subId));
|
||||
final NetworkPolicy policy = mNetworkPolicy.get(template);
|
||||
if (policy != null) {
|
||||
return new SubscriptionPlan[] { SubscriptionPlan.convert(policy) };
|
||||
} else {
|
||||
return new SubscriptionPlan[0];
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
synchronized (mNetworkPoliciesSecondLock) {
|
||||
return mSubscriptionPlans.get(subId);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2635,36 +2719,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) {
|
||||
enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
|
||||
|
||||
// TODO: extend to support external data sources
|
||||
if (!"com.android.settings".equals(callingPackage)) {
|
||||
throw new UnsupportedOperationException();
|
||||
for (SubscriptionPlan plan : plans) {
|
||||
Preconditions.checkNotNull(plan);
|
||||
}
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
|
||||
final NetworkTemplate template = NetworkTemplate
|
||||
.buildTemplateMobileAll(tm.getSubscriberId(subId));
|
||||
if (ArrayUtils.isEmpty(plans)) {
|
||||
mNetworkPolicy.remove(template);
|
||||
} else {
|
||||
final NetworkPolicy policy = SubscriptionPlan.convert(plans[0]);
|
||||
policy.template = template;
|
||||
mNetworkPolicy.put(template, policy);
|
||||
maybeRefreshTrustedTime();
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
synchronized (mNetworkPoliciesSecondLock) {
|
||||
mSubscriptionPlans.put(subId, plans);
|
||||
// TODO: update any implicit details from newly defined plans
|
||||
handleNetworkPoliciesUpdateAL(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubscriptionPlanOwner(int subId) {
|
||||
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
|
||||
|
||||
// TODO: extend to support external data sources
|
||||
return "com.android.settings";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
|
||||
|
||||
@@ -34,7 +34,6 @@ import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEF
|
||||
import static android.telephony.CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG;
|
||||
import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG;
|
||||
import static android.telephony.CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT;
|
||||
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||
import static android.text.format.Time.TIMEZONE_UTC;
|
||||
|
||||
@@ -92,7 +91,6 @@ import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.NetworkPolicy;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkState;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.NetworkTemplate;
|
||||
@@ -108,12 +106,12 @@ import android.support.test.filters.MediumTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.SubscriptionPlan;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.Time;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.RecurrenceRule;
|
||||
import android.util.TrustedTime;
|
||||
|
||||
import com.android.internal.telephony.PhoneConstants;
|
||||
@@ -154,7 +152,10 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@@ -396,7 +397,7 @@ public class NetworkPolicyManagerServiceTest {
|
||||
|
||||
@After
|
||||
public void resetClock() throws Exception {
|
||||
SubscriptionPlan.sNowOverride = -1;
|
||||
RecurrenceRule.sClock = Clock.systemDefaultZone();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -785,9 +786,9 @@ public class NetworkPolicyManagerServiceTest {
|
||||
}
|
||||
|
||||
private static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
|
||||
SubscriptionPlan.sNowOverride = currentTime;
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = NetworkPolicyManager
|
||||
.cycleIterator(policy);
|
||||
RecurrenceRule.sClock = Clock.fixed(Instant.ofEpochMilli(currentTime),
|
||||
ZoneId.systemDefault());
|
||||
final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = policy.cycleIterator();
|
||||
while (it.hasNext()) {
|
||||
final Pair<ZonedDateTime, ZonedDateTime> cycle = it.next();
|
||||
if (cycle.first.toInstant().toEpochMilli() < currentTime) {
|
||||
@@ -799,8 +800,9 @@ public class NetworkPolicyManagerServiceTest {
|
||||
}
|
||||
|
||||
private static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
|
||||
SubscriptionPlan.sNowOverride = currentTime;
|
||||
return NetworkPolicyManager.cycleIterator(policy).next().second.toInstant().toEpochMilli();
|
||||
RecurrenceRule.sClock = Clock.fixed(Instant.ofEpochMilli(currentTime),
|
||||
ZoneId.systemDefault());
|
||||
return policy.cycleIterator().next().second.toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -893,38 +895,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
computeNextCycleBoundary(parseTime("2012-01-05T00:00:00.000Z"), policy));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextCycleSane() throws Exception {
|
||||
final NetworkPolicy policy = new NetworkPolicy(
|
||||
sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
|
||||
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
|
||||
|
||||
// walk forwards, ensuring that cycle boundaries don't get stuck
|
||||
long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
long nextCycle = computeNextCycleBoundary(currentCycle, policy);
|
||||
assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
|
||||
assertUnique(seen, nextCycle);
|
||||
currentCycle = nextCycle;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastCycleSane() throws Exception {
|
||||
final NetworkPolicy policy = new NetworkPolicy(
|
||||
sTemplateWifi, 31, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, false);
|
||||
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
|
||||
|
||||
// walk backwards, ensuring that cycle boundaries look sane
|
||||
long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
long lastCycle = computeLastCycleBoundary(currentCycle, policy);
|
||||
assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
|
||||
assertUnique(seen, lastCycle);
|
||||
currentCycle = lastCycle;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCycleTodayJanuary() throws Exception {
|
||||
final NetworkPolicy policy = new NetworkPolicy(
|
||||
@@ -945,17 +915,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
computeLastCycleBoundary(parseTime("2013-01-14T15:11:00.000-08:00"), policy));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastCycleBoundaryDST() throws Exception {
|
||||
final long currentTime = parseTime("1989-01-02T07:30:00.000Z");
|
||||
final long expectedCycle = parseTime("1988-12-03T02:00:00.000Z");
|
||||
|
||||
final NetworkPolicy policy = new NetworkPolicy(
|
||||
sTemplateWifi, 3, "America/Argentina/Buenos_Aires", 1024L, 1024L, false);
|
||||
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
|
||||
assertTimeEquals(expectedCycle, actualCycle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
|
||||
NetworkState[] state = null;
|
||||
@@ -1144,15 +1103,6 @@ public class NetworkPolicyManagerServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConversion() throws Exception {
|
||||
NetworkTemplate template = NetworkTemplate.buildTemplateMobileWildcard();
|
||||
NetworkPolicy before = new NetworkPolicy(template, 12, "Israel", 123, 456, true);
|
||||
NetworkPolicy after = SubscriptionPlan.convert(SubscriptionPlan.convert(before));
|
||||
after.template = before.template;
|
||||
assertEquals(before, after);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnUidStateChanged_notifyAMS() throws Exception {
|
||||
final long procStateSeq = 222;
|
||||
@@ -1472,7 +1422,9 @@ public class NetworkPolicyManagerServiceTest {
|
||||
private NetworkPolicy buildDefaultFakeMobilePolicy() {
|
||||
NetworkPolicy p = mService.buildDefaultMobilePolicy(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
|
||||
// set a deterministic cycle date
|
||||
p.cycleDay = DEFAULT_CYCLE_DAY;
|
||||
p.cycleRule = new RecurrenceRule(
|
||||
p.cycleRule.start.withDayOfMonth(DEFAULT_CYCLE_DAY),
|
||||
p.cycleRule.end, Period.ofMonths(1));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1665,7 +1617,8 @@ public class NetworkPolicyManagerServiceTest {
|
||||
}
|
||||
|
||||
private void setCurrentTimeMillis(long currentTimeMillis) {
|
||||
SubscriptionPlan.sNowOverride = currentTimeMillis;
|
||||
RecurrenceRule.sClock = Clock.fixed(Instant.ofEpochMilli(currentTimeMillis),
|
||||
ZoneId.systemDefault());
|
||||
mStartTime = currentTimeMillis;
|
||||
mElapsedRealtime = 0L;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.content.Context;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.service.carrier.CarrierService;
|
||||
|
||||
import com.android.ims.ImsReasonInfo;
|
||||
import com.android.internal.telephony.ICarrierConfigLoader;
|
||||
@@ -261,6 +262,17 @@ public class CarrierConfigManager {
|
||||
public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING =
|
||||
"config_ims_package_override_string";
|
||||
|
||||
/**
|
||||
* Override the package that will manage {@link SubscriptionPlan}
|
||||
* information instead of the {@link CarrierService} that defines this
|
||||
* value.
|
||||
*
|
||||
* @see SubscriptionManager#getSubscriptionPlans(int)
|
||||
* @see SubscriptionManager#setSubscriptionPlans(int, java.util.List)
|
||||
*/
|
||||
public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING =
|
||||
"config_plans_package_override_string";
|
||||
|
||||
/**
|
||||
* Override the platform's notion of a network operator being considered roaming.
|
||||
* Value is string array of SIDs to be considered roaming for 3GPP2 RATs.
|
||||
@@ -1379,12 +1391,16 @@ public class CarrierConfigManager {
|
||||
/**
|
||||
* The day of the month (1-31) on which the data cycle rolls over.
|
||||
* <p>
|
||||
* If the current month does not have this day, the cycle will roll over at the start of the
|
||||
* next month.
|
||||
* If the current month does not have this day, the cycle will roll over at
|
||||
* the start of the next month.
|
||||
* <p>
|
||||
* This setting may be still overridden by explicit user choice. By default, the platform value
|
||||
* will be used.
|
||||
* This setting may be still overridden by explicit user choice. By default,
|
||||
* the platform value will be used.
|
||||
*
|
||||
* @deprecated replaced by
|
||||
* {@link SubscriptionManager#setSubscriptionPlans(int, java.util.List)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT =
|
||||
"monthly_data_cycle_day_int";
|
||||
|
||||
@@ -1395,6 +1411,7 @@ public class CarrierConfigManager {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1;
|
||||
|
||||
/**
|
||||
@@ -1408,6 +1425,7 @@ public class CarrierConfigManager {
|
||||
* default data limit, if one exists, will be disabled. A user selected data limit will not be
|
||||
* overridden.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2;
|
||||
|
||||
/**
|
||||
@@ -1420,7 +1438,11 @@ public class CarrierConfigManager {
|
||||
* <p>
|
||||
* This setting may be overridden by explicit user choice. By default, the platform value
|
||||
* will be used.
|
||||
*
|
||||
* @deprecated replaced by
|
||||
* {@link SubscriptionManager#setSubscriptionPlans(int, java.util.List)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG =
|
||||
"data_warning_threshold_bytes_long";
|
||||
|
||||
@@ -1434,7 +1456,11 @@ public class CarrierConfigManager {
|
||||
* <p>
|
||||
* This setting may be overridden by explicit user choice. By default, the platform value
|
||||
* will be used.
|
||||
*
|
||||
* @deprecated replaced by
|
||||
* {@link SubscriptionManager#setSubscriptionPlans(int, java.util.List)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG =
|
||||
"data_limit_threshold_bytes_long";
|
||||
|
||||
@@ -1866,6 +1892,15 @@ public class CarrierConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public String getDefaultCarrierServicePackageName() {
|
||||
try {
|
||||
return getICarrierConfigLoader().getDefaultCarrierServicePackageName();
|
||||
} catch (Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new bundle with the default value for every supported configuration variable.
|
||||
*
|
||||
|
||||
@@ -18,8 +18,8 @@ package android.telephony;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
@@ -1542,7 +1542,20 @@ public class SubscriptionManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@pending} */
|
||||
/**
|
||||
* Get the description of the billing relationship plan between a carrier
|
||||
* and a specific subscriber.
|
||||
* <p>
|
||||
* This method is only accessible to the following narrow set of apps:
|
||||
* <ul>
|
||||
* <li>The carrier app for this subscriberId, as determined by
|
||||
* {@link TelephonyManager#hasCarrierPrivileges(int)}.
|
||||
* <li>The carrier app explicitly delegated access through
|
||||
* {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
|
||||
* </ul>
|
||||
*
|
||||
* @param subId the subscriber this relationship applies to
|
||||
*/
|
||||
public @NonNull List<SubscriptionPlan> getSubscriptionPlans(int subId) {
|
||||
final INetworkPolicyManager npm = INetworkPolicyManager.Stub
|
||||
.asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
||||
@@ -1554,7 +1567,23 @@ public class SubscriptionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@pending} */
|
||||
/**
|
||||
* Set the description of the billing relationship plan between a carrier
|
||||
* and a specific subscriber.
|
||||
* <p>
|
||||
* This method is only accessible to the following narrow set of apps:
|
||||
* <ul>
|
||||
* <li>The carrier app for this subscriberId, as determined by
|
||||
* {@link TelephonyManager#hasCarrierPrivileges(int)}.
|
||||
* <li>The carrier app explicitly delegated access through
|
||||
* {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
|
||||
* </ul>
|
||||
*
|
||||
* @param subId the subscriber this relationship applies to
|
||||
* @param plans the list of plans. The first plan is always the primary and
|
||||
* most important plan. Any additional plans are secondary and
|
||||
* may not be displayed or used by decision making logic.
|
||||
*/
|
||||
public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
|
||||
final INetworkPolicyManager npm = INetworkPolicyManager.Stub
|
||||
.asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
||||
@@ -1565,15 +1594,4 @@ public class SubscriptionManager {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public String getSubscriptionPlanOwner(int subId) {
|
||||
final INetworkPolicyManager npm = INetworkPolicyManager.Stub
|
||||
.asInterface(ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
|
||||
try {
|
||||
return npm.getSubscriptionPlanOwner(subId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,45 +19,31 @@ package android.telephony;
|
||||
import android.annotation.BytesLong;
|
||||
import android.annotation.CurrentTimeMillisLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.NetworkPolicy;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.RecurrenceRule;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.Period;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.Iterator;
|
||||
|
||||
/** {@pending} */
|
||||
/**
|
||||
* Description of a billing relationship plan between a carrier and a specific
|
||||
* subscriber. This information is used to present more useful UI to users, such
|
||||
* as explaining how much mobile data they have remaining, and what will happen
|
||||
* when they run out.
|
||||
*
|
||||
* @see SubscriptionManager#setSubscriptionPlans(int, java.util.List)
|
||||
* @see SubscriptionManager#getSubscriptionPlans(int)
|
||||
*/
|
||||
public final class SubscriptionPlan implements Parcelable {
|
||||
private static final String TAG = "SubscriptionPlan";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/** {@hide} */
|
||||
@IntDef(prefix = "TYPE_", value = {
|
||||
TYPE_NONRECURRING,
|
||||
TYPE_RECURRING_WEEKLY,
|
||||
TYPE_RECURRING_MONTHLY,
|
||||
TYPE_RECURRING_DAILY,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Type {}
|
||||
|
||||
public static final int TYPE_NONRECURRING = 0;
|
||||
public static final int TYPE_RECURRING_MONTHLY = 1;
|
||||
public static final int TYPE_RECURRING_WEEKLY = 2;
|
||||
public static final int TYPE_RECURRING_DAILY = 3;
|
||||
|
||||
/** {@hide} */
|
||||
@IntDef(prefix = "LIMIT_BEHAVIOR_", value = {
|
||||
LIMIT_BEHAVIOR_UNKNOWN,
|
||||
@@ -68,51 +54,40 @@ public final class SubscriptionPlan implements Parcelable {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LimitBehavior {}
|
||||
|
||||
/** When a resource limit is hit, the behavior is unknown. */
|
||||
public static final int LIMIT_BEHAVIOR_UNKNOWN = -1;
|
||||
/** When a resource limit is hit, access is disabled. */
|
||||
public static final int LIMIT_BEHAVIOR_DISABLED = 0;
|
||||
/** When a resource limit is hit, the user is billed automatically. */
|
||||
public static final int LIMIT_BEHAVIOR_BILLED = 1;
|
||||
/** When a resource limit is hit, access is throttled to a slower rate. */
|
||||
public static final int LIMIT_BEHAVIOR_THROTTLED = 2;
|
||||
|
||||
/** Value indicating a number of bytes is unknown. */
|
||||
public static final long BYTES_UNKNOWN = -1;
|
||||
/** Value indicating a number of bytes is unlimited. */
|
||||
public static final long BYTES_UNLIMITED = Long.MAX_VALUE;
|
||||
|
||||
/** Value indicating a timestamp is unknown. */
|
||||
public static final long TIME_UNKNOWN = -1;
|
||||
|
||||
private final int type;
|
||||
private final ZonedDateTime start;
|
||||
private final ZonedDateTime end;
|
||||
private final RecurrenceRule cycleRule;
|
||||
private CharSequence title;
|
||||
private CharSequence summary;
|
||||
private long dataWarningBytes = BYTES_UNKNOWN;
|
||||
private long dataWarningSnoozeTime = TIME_UNKNOWN;
|
||||
private long dataLimitBytes = BYTES_UNKNOWN;
|
||||
private long dataLimitSnoozeTime = TIME_UNKNOWN;
|
||||
private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN;
|
||||
private long dataUsageBytes = BYTES_UNKNOWN;
|
||||
private long dataUsageTime = TIME_UNKNOWN;
|
||||
|
||||
private SubscriptionPlan(@Type int type, ZonedDateTime start, ZonedDateTime end) {
|
||||
this.type = type;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
private SubscriptionPlan(RecurrenceRule cycleRule) {
|
||||
this.cycleRule = Preconditions.checkNotNull(cycleRule);
|
||||
}
|
||||
|
||||
private SubscriptionPlan(Parcel source) {
|
||||
type = source.readInt();
|
||||
if (source.readInt() != 0) {
|
||||
start = ZonedDateTime.parse(source.readString());
|
||||
} else {
|
||||
start = null;
|
||||
}
|
||||
if (source.readInt() != 0) {
|
||||
end = ZonedDateTime.parse(source.readString());
|
||||
} else {
|
||||
end = null;
|
||||
}
|
||||
cycleRule = source.readParcelable(null);
|
||||
title = source.readCharSequence();
|
||||
summary = source.readCharSequence();
|
||||
dataWarningBytes = source.readLong();
|
||||
dataWarningSnoozeTime = source.readLong();
|
||||
dataLimitBytes = source.readLong();
|
||||
dataLimitSnoozeTime = source.readLong();
|
||||
dataLimitBehavior = source.readInt();
|
||||
dataUsageBytes = source.readLong();
|
||||
dataUsageTime = source.readLong();
|
||||
@@ -125,25 +100,10 @@ public final class SubscriptionPlan implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(type);
|
||||
if (start != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeString(start.toString());
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (end != null) {
|
||||
dest.writeInt(1);
|
||||
dest.writeString(end.toString());
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
dest.writeParcelable(cycleRule, flags);
|
||||
dest.writeCharSequence(title);
|
||||
dest.writeCharSequence(summary);
|
||||
dest.writeLong(dataWarningBytes);
|
||||
dest.writeLong(dataWarningSnoozeTime);
|
||||
dest.writeLong(dataLimitBytes);
|
||||
dest.writeLong(dataLimitSnoozeTime);
|
||||
dest.writeInt(dataLimitBehavior);
|
||||
dest.writeLong(dataUsageBytes);
|
||||
dest.writeLong(dataUsageTime);
|
||||
@@ -151,20 +111,15 @@ public final class SubscriptionPlan implements Parcelable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("SubscriptionPlan:")
|
||||
.append(" type=").append(type)
|
||||
.append(" start=").append(start)
|
||||
.append(" end=").append(end)
|
||||
return new StringBuilder("SubscriptionPlan{")
|
||||
.append("cycleRule=").append(cycleRule)
|
||||
.append(" title=").append(title)
|
||||
.append(" summary=").append(summary)
|
||||
.append(" dataWarningBytes=").append(dataWarningBytes)
|
||||
.append(" dataWarningSnoozeTime=").append(dataWarningSnoozeTime)
|
||||
.append(" dataLimitBytes=").append(dataLimitBytes)
|
||||
.append(" dataLimitSnoozeTime=").append(dataLimitSnoozeTime)
|
||||
.append(" dataLimitBehavior=").append(dataLimitBehavior)
|
||||
.append(" dataUsageBytes=").append(dataUsageBytes)
|
||||
.append(" dataUsageTime=").append(dataUsageTime)
|
||||
.toString();
|
||||
.append("}").toString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SubscriptionPlan> CREATOR = new Parcelable.Creator<SubscriptionPlan>() {
|
||||
@@ -179,296 +134,161 @@ public final class SubscriptionPlan implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public @Type int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ZonedDateTime getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public ZonedDateTime getEnd() {
|
||||
return end;
|
||||
/** {@hide} */
|
||||
public @NonNull RecurrenceRule getCycleRule() {
|
||||
return cycleRule;
|
||||
}
|
||||
|
||||
/** Return the short title of this plan. */
|
||||
public @Nullable CharSequence getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/** Return the short summary of this plan. */
|
||||
public @Nullable CharSequence getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public @BytesLong long getDataWarningBytes() {
|
||||
return dataWarningBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the usage threshold at which data access changes according to
|
||||
* {@link #getDataLimitBehavior()}.
|
||||
*/
|
||||
public @BytesLong long getDataLimitBytes() {
|
||||
return dataLimitBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the behavior of data access when usage reaches
|
||||
* {@link #getDataLimitBytes()}.
|
||||
*/
|
||||
public @LimitBehavior int getDataLimitBehavior() {
|
||||
return dataLimitBehavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a snapshot of currently known mobile data usage at
|
||||
* {@link #getDataUsageTime()}.
|
||||
*/
|
||||
public @BytesLong long getDataUsageBytes() {
|
||||
return dataUsageBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time at which {@link #getDataUsageBytes()} was valid.
|
||||
*/
|
||||
public @CurrentTimeMillisLong long getDataUsageTime() {
|
||||
return dataUsageTime;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@VisibleForTesting
|
||||
public static long sNowOverride = -1;
|
||||
|
||||
private static ZonedDateTime now(ZoneId zone) {
|
||||
return (sNowOverride != -1)
|
||||
? ZonedDateTime.ofInstant(Instant.ofEpochMilli(sNowOverride), zone)
|
||||
: ZonedDateTime.now(zone);
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public static SubscriptionPlan convert(NetworkPolicy policy) {
|
||||
final ZoneId zone = ZoneId.of(policy.cycleTimezone);
|
||||
final ZonedDateTime now = now(zone);
|
||||
final Builder builder;
|
||||
if (policy.cycleDay != NetworkPolicy.CYCLE_NONE) {
|
||||
// Assume we started last January, since it has all possible days
|
||||
ZonedDateTime start = ZonedDateTime.of(
|
||||
now.toLocalDate().minusYears(1).withMonth(1).withDayOfMonth(policy.cycleDay),
|
||||
LocalTime.MIDNIGHT, zone);
|
||||
builder = Builder.createRecurringMonthly(start);
|
||||
} else {
|
||||
Log.w(TAG, "Cycle not defined; assuming last 4 weeks non-recurring");
|
||||
ZonedDateTime end = now;
|
||||
ZonedDateTime start = end.minusWeeks(4);
|
||||
builder = Builder.createNonrecurring(start, end);
|
||||
}
|
||||
if (policy.warningBytes != NetworkPolicy.WARNING_DISABLED) {
|
||||
builder.setDataWarning(policy.warningBytes);
|
||||
}
|
||||
if (policy.lastWarningSnooze != NetworkPolicy.SNOOZE_NEVER) {
|
||||
builder.setDataWarningSnooze(policy.lastWarningSnooze);
|
||||
}
|
||||
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
|
||||
builder.setDataLimit(policy.limitBytes, LIMIT_BEHAVIOR_DISABLED);
|
||||
}
|
||||
if (policy.lastLimitSnooze != NetworkPolicy.SNOOZE_NEVER) {
|
||||
builder.setDataLimitSnooze(policy.lastLimitSnooze);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public static NetworkPolicy convert(SubscriptionPlan plan) {
|
||||
final NetworkPolicy policy = new NetworkPolicy();
|
||||
switch (plan.type) {
|
||||
case TYPE_RECURRING_MONTHLY:
|
||||
policy.cycleDay = plan.start.getDayOfMonth();
|
||||
policy.cycleTimezone = plan.start.getZone().getId();
|
||||
break;
|
||||
default:
|
||||
policy.cycleDay = NetworkPolicy.CYCLE_NONE;
|
||||
policy.cycleTimezone = "UTC";
|
||||
break;
|
||||
}
|
||||
policy.warningBytes = plan.dataWarningBytes;
|
||||
policy.limitBytes = plan.dataLimitBytes;
|
||||
policy.lastWarningSnooze = plan.dataWarningSnoozeTime;
|
||||
policy.lastLimitSnooze = plan.dataLimitSnoozeTime;
|
||||
policy.metered = true;
|
||||
policy.inferred = false;
|
||||
return policy;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public TemporalUnit getTemporalUnit() {
|
||||
switch (type) {
|
||||
case TYPE_RECURRING_DAILY: return ChronoUnit.DAYS;
|
||||
case TYPE_RECURRING_WEEKLY: return ChronoUnit.WEEKS;
|
||||
case TYPE_RECURRING_MONTHLY: return ChronoUnit.MONTHS;
|
||||
default: throw new IllegalArgumentException();
|
||||
}
|
||||
/**
|
||||
* Return an iterator that will return all valid data usage cycles based on
|
||||
* any recurrence rules. The iterator starts from the currently active cycle
|
||||
* and walks backwards through time.
|
||||
*/
|
||||
public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
|
||||
return cycleRule.cycleIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator that returns data usage cycles.
|
||||
* <p>
|
||||
* For recurring plans, it starts at the currently active cycle, and then
|
||||
* walks backwards in time through each previous cycle, back to the defined
|
||||
* starting point and no further.
|
||||
* <p>
|
||||
* For non-recurring plans, it returns one single cycle.
|
||||
* Builder for a {@link SubscriptionPlan}.
|
||||
*/
|
||||
public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
|
||||
switch (type) {
|
||||
case TYPE_NONRECURRING:
|
||||
return new NonrecurringIterator();
|
||||
case TYPE_RECURRING_WEEKLY:
|
||||
case TYPE_RECURRING_MONTHLY:
|
||||
case TYPE_RECURRING_DAILY:
|
||||
return new RecurringIterator();
|
||||
default:
|
||||
throw new IllegalStateException("Unknown type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private class NonrecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
|
||||
boolean hasNext = true;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<ZonedDateTime, ZonedDateTime> next() {
|
||||
hasNext = false;
|
||||
return new Pair<>(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
private class RecurringIterator implements Iterator<Pair<ZonedDateTime, ZonedDateTime>> {
|
||||
TemporalUnit unit;
|
||||
long i;
|
||||
ZonedDateTime cycleStart;
|
||||
ZonedDateTime cycleEnd;
|
||||
|
||||
public RecurringIterator() {
|
||||
final ZonedDateTime now = now(start.getZone());
|
||||
if (DEBUG) Log.d(TAG, "Resolving using now " + now);
|
||||
|
||||
unit = getTemporalUnit();
|
||||
i = unit.between(start, now);
|
||||
updateCycle();
|
||||
|
||||
// Walk forwards until we find first cycle after now
|
||||
while (cycleEnd.toEpochSecond() <= now.toEpochSecond()) {
|
||||
i++;
|
||||
updateCycle();
|
||||
}
|
||||
|
||||
// Walk backwards until we find first cycle before now
|
||||
while (cycleStart.toEpochSecond() > now.toEpochSecond()) {
|
||||
i--;
|
||||
updateCycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCycle() {
|
||||
cycleStart = roundBoundaryTime(start.plus(i, unit));
|
||||
cycleEnd = roundBoundaryTime(start.plus(i + 1, unit));
|
||||
}
|
||||
|
||||
private ZonedDateTime roundBoundaryTime(ZonedDateTime boundary) {
|
||||
if ((type == TYPE_RECURRING_MONTHLY)
|
||||
&& (boundary.getDayOfMonth() < start.getDayOfMonth())) {
|
||||
// When forced to end a monthly cycle early, we want to count
|
||||
// that entire day against the boundary.
|
||||
return ZonedDateTime.of(boundary.toLocalDate(), LocalTime.MAX, start.getZone());
|
||||
} else {
|
||||
return boundary;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return cycleStart.toEpochSecond() >= start.toEpochSecond();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<ZonedDateTime, ZonedDateTime> next() {
|
||||
if (DEBUG) Log.d(TAG, "Cycle " + i + " from " + cycleStart + " to " + cycleEnd);
|
||||
Pair<ZonedDateTime, ZonedDateTime> p = new Pair<>(cycleStart, cycleEnd);
|
||||
i--;
|
||||
updateCycle();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final SubscriptionPlan plan;
|
||||
|
||||
private Builder(@Type int type, ZonedDateTime start, ZonedDateTime end) {
|
||||
plan = new SubscriptionPlan(type, start, end);
|
||||
/** {@hide} */
|
||||
public Builder(ZonedDateTime start, ZonedDateTime end, Period period) {
|
||||
plan = new SubscriptionPlan(new RecurrenceRule(start, end, period));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start defining a {@link SubscriptionPlan} that covers a very specific
|
||||
* window of time, and never automatically recurs.
|
||||
*/
|
||||
public static Builder createNonrecurring(ZonedDateTime start, ZonedDateTime end) {
|
||||
if (!end.isAfter(start)) {
|
||||
throw new IllegalArgumentException(
|
||||
"End " + end + " isn't after start " + start);
|
||||
}
|
||||
return new Builder(TYPE_NONRECURRING, start, end);
|
||||
return new Builder(start, end, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start defining a {@link SubscriptionPlan} that will recur
|
||||
* automatically every month. It will always recur on the same day of a
|
||||
* particular month. When a particular month ends before the defined
|
||||
* recurrence day, the plan will recur on the last instant of that
|
||||
* month.
|
||||
*/
|
||||
public static Builder createRecurringMonthly(ZonedDateTime start) {
|
||||
return new Builder(TYPE_RECURRING_MONTHLY, start, null);
|
||||
return new Builder(start, null, Period.ofMonths(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start defining a {@link SubscriptionPlan} that will recur
|
||||
* automatically every week.
|
||||
*/
|
||||
public static Builder createRecurringWeekly(ZonedDateTime start) {
|
||||
return new Builder(TYPE_RECURRING_WEEKLY, start, null);
|
||||
return new Builder(start, null, Period.ofDays(7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start defining a {@link SubscriptionPlan} that will recur
|
||||
* automatically every day.
|
||||
*/
|
||||
public static Builder createRecurringDaily(ZonedDateTime start) {
|
||||
return new Builder(TYPE_RECURRING_DAILY, start, null);
|
||||
return new Builder(start, null, Period.ofDays(1));
|
||||
}
|
||||
|
||||
public SubscriptionPlan build() {
|
||||
return plan;
|
||||
}
|
||||
|
||||
/** Set the short title of this plan. */
|
||||
public Builder setTitle(@Nullable CharSequence title) {
|
||||
plan.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Set the short summary of this plan. */
|
||||
public Builder setSummary(@Nullable CharSequence summary) {
|
||||
plan.summary = summary;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDataWarning(@BytesLong long dataWarningBytes) {
|
||||
if (dataWarningBytes < BYTES_UNKNOWN) {
|
||||
throw new IllegalArgumentException("Warning must be positive or BYTES_UNKNOWN");
|
||||
}
|
||||
plan.dataWarningBytes = dataWarningBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public Builder setDataWarningSnooze(@CurrentTimeMillisLong long dataWarningSnoozeTime) {
|
||||
plan.dataWarningSnoozeTime = dataWarningSnoozeTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the usage threshold at which data access changes.
|
||||
*
|
||||
* @param dataLimitBytes the usage threshold at which data access
|
||||
* changes
|
||||
* @param dataLimitBehavior the behavior of data access when usage
|
||||
* reaches the threshold
|
||||
*/
|
||||
public Builder setDataLimit(@BytesLong long dataLimitBytes,
|
||||
@LimitBehavior int dataLimitBehavior) {
|
||||
if (dataLimitBytes < BYTES_UNKNOWN) {
|
||||
throw new IllegalArgumentException("Limit must be positive or BYTES_UNKNOWN");
|
||||
if (dataLimitBytes < 0) {
|
||||
throw new IllegalArgumentException("Limit bytes must be positive");
|
||||
}
|
||||
if (dataLimitBehavior < 0) {
|
||||
throw new IllegalArgumentException("Limit behavior must be defined");
|
||||
}
|
||||
plan.dataLimitBytes = dataLimitBytes;
|
||||
plan.dataLimitBehavior = dataLimitBehavior;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public Builder setDataLimitSnooze(@CurrentTimeMillisLong long dataLimitSnoozeTime) {
|
||||
plan.dataLimitSnoozeTime = dataLimitSnoozeTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a snapshot of currently known mobile data usage.
|
||||
*
|
||||
* @param dataUsageBytes the currently known mobile data usage
|
||||
* @param dataUsageTime the time at which this snapshot was valid
|
||||
*/
|
||||
public Builder setDataUsage(@BytesLong long dataUsageBytes,
|
||||
@CurrentTimeMillisLong long dataUsageTime) {
|
||||
if (dataUsageBytes < BYTES_UNKNOWN) {
|
||||
throw new IllegalArgumentException("Usage must be positive or BYTES_UNKNOWN");
|
||||
if (dataUsageBytes < 0) {
|
||||
throw new IllegalArgumentException("Usage bytes must be positive");
|
||||
}
|
||||
if (dataUsageTime < TIME_UNKNOWN) {
|
||||
throw new IllegalArgumentException("Time must be positive or TIME_UNKNOWN");
|
||||
}
|
||||
if ((dataUsageBytes == BYTES_UNKNOWN) != (dataUsageTime == TIME_UNKNOWN)) {
|
||||
throw new IllegalArgumentException("Must provide both usage and time or neither");
|
||||
if (dataUsageTime < 0) {
|
||||
throw new IllegalArgumentException("Usage time must be positive");
|
||||
}
|
||||
plan.dataUsageBytes = dataUsageBytes;
|
||||
plan.dataUsageTime = dataUsageTime;
|
||||
|
||||
@@ -28,4 +28,7 @@ interface ICarrierConfigLoader {
|
||||
void notifyConfigChangedForSubId(int subId);
|
||||
|
||||
void updateConfigForPhoneId(int phoneId, String simState);
|
||||
|
||||
String getDefaultCarrierServicePackageName();
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user