diff options
56 files changed, 1274 insertions, 2537 deletions
diff --git a/api/current.txt b/api/current.txt index 15354357e293..2428da1a4390 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37768,8 +37768,10 @@ package android.service.wallpaper { method public android.view.SurfaceHolder getSurfaceHolder(); method public boolean isPreview(); method public boolean isVisible(); + method public void notifyColorsChanged(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -39536,7 +39538,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 +39580,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 +39640,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 +40152,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 +40169,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); @@ -52264,6 +52301,11 @@ package dalvik.system { method protected synchronized java.lang.Package getPackage(java.lang.String); } + public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader { + ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader); + ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader); + } + public class DexClassLoader extends dalvik.system.BaseDexClassLoader { ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader); } diff --git a/api/system-current.txt b/api/system-current.txt index 8e3c840fa8ab..47e47ac6f1be 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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"; @@ -41097,8 +41096,10 @@ package android.service.wallpaper { method public android.view.SurfaceHolder getSurfaceHolder(); method public boolean isPreview(); method public boolean isVisible(); + method public void notifyColorsChanged(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -43083,7 +43084,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 +43126,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 +43186,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 +43700,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 +43717,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); @@ -56294,6 +56330,11 @@ package dalvik.system { method protected synchronized java.lang.Package getPackage(java.lang.String); } + public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader { + ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader); + ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader); + } + public class DexClassLoader extends dalvik.system.BaseDexClassLoader { ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader); } diff --git a/api/test-current.txt b/api/test-current.txt index cbf8e0610967..62f8418b4a71 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -37978,8 +37978,10 @@ package android.service.wallpaper { method public android.view.SurfaceHolder getSurfaceHolder(); method public boolean isPreview(); method public boolean isVisible(); + method public void notifyColorsChanged(); method public void onApplyWindowInsets(android.view.WindowInsets); method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean); + method public android.app.WallpaperColors onComputeColors(); method public void onCreate(android.view.SurfaceHolder); method public void onDesiredSizeChanged(int, int); method public void onDestroy(); @@ -39762,7 +39764,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 +39806,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 +39866,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 +40378,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 +40395,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); @@ -52701,6 +52738,11 @@ package dalvik.system { method protected synchronized java.lang.Package getPackage(java.lang.String); } + public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader { + ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader); + ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader); + } + public class DexClassLoader extends dalvik.system.BaseDexClassLoader { ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 7b948a7a933e..181e4a26d9b8 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -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); } diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index edf9a28d27f5..5df742c5a394 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -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); } } diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 3fe9b0d74538..81c49a339d53 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -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(); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f5597b8eac8e..53c82e6c5237 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10132,22 +10132,6 @@ public final class Settings { public static final String DEVICE_DEMO_MODE = "device_demo_mode"; /** - * Retail mode specific settings. This is encoded as a key=value list, separated by commas. - * Ex: "user_inactivity_timeout_ms=30000,warning_dialog_timeout_ms=10000". The following - * keys are supported: - * - * <pre> - * user_inactivity_timeout_ms (long) - * warning_dialog_timeout_ms (long) - * </pre> - * <p> - * Type: string - * - * @hide - */ - public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants"; - - /** * Indicates the maximum time that an app is blocked for the network rules to get updated. * * Type: long diff --git a/core/java/android/service/vr/IVrListener.aidl b/core/java/android/service/vr/IVrListener.aidl index afb13d316503..acca3fa66ae4 100644 --- a/core/java/android/service/vr/IVrListener.aidl +++ b/core/java/android/service/vr/IVrListener.aidl @@ -20,5 +20,5 @@ import android.content.ComponentName; /** @hide */ oneway interface IVrListener { - void focusedActivityChanged(in ComponentName component); + void focusedActivityChanged(in ComponentName component, boolean running2dInVr, int pid); } diff --git a/core/java/android/service/vr/VrListenerService.java b/core/java/android/service/vr/VrListenerService.java index 5da4560f688d..fa3d065d28a7 100644 --- a/core/java/android/service/vr/VrListenerService.java +++ b/core/java/android/service/vr/VrListenerService.java @@ -70,8 +70,10 @@ public abstract class VrListenerService extends Service { private final IVrListener.Stub mBinder = new IVrListener.Stub() { @Override - public void focusedActivityChanged(ComponentName component) { - mHandler.obtainMessage(MSG_ON_CURRENT_VR_ACTIVITY_CHANGED, component).sendToTarget(); + public void focusedActivityChanged( + ComponentName component, boolean running2dInVr, int pid) { + mHandler.obtainMessage(MSG_ON_CURRENT_VR_ACTIVITY_CHANGED, running2dInVr ? 1 : 0, + pid, component).sendToTarget(); } }; @@ -84,7 +86,8 @@ public abstract class VrListenerService extends Service { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ON_CURRENT_VR_ACTIVITY_CHANGED: { - VrListenerService.this.onCurrentVrActivityChanged((ComponentName) msg.obj); + VrListenerService.this.onCurrentVrActivityChanged( + (ComponentName) msg.obj, msg.arg1 == 1, msg.arg2); } break; } } @@ -120,6 +123,29 @@ public abstract class VrListenerService extends Service { } /** + * An extended version of onCurrentVrActivityChanged + * + * <p>This will be called when this service is initially bound, but is not + * guaranteed to be called before onUnbind. In general, this is intended to be used to + * determine when user focus has transitioned between two VR activities, or between a + * VR activity and a 2D activity. This should be overridden instead of the above + * onCurrentVrActivityChanged as that version is deprecated.</p> + * + * @param component the {@link ComponentName} of the VR activity or the 2D intent. + * @param running2dInVr true if the component is a 2D component. + * @param pid the process the component is running in. + * + * @see android.app.Activity#setVrModeEnabled + * @see android.R.attr#enableVrMode + * @hide + */ + public void onCurrentVrActivityChanged( + ComponentName component, boolean running2dInVr, int pid) { + // Override to implement. Default to old behaviour of sending null for 2D. + onCurrentVrActivityChanged(running2dInVr ? null : component); + } + + /** * Checks if the given component is enabled in user settings. * * <p>If this component is not enabled in the user's settings, it will not be started when diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index e4d3142ccefe..424967f0e011 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -547,12 +547,11 @@ public abstract class WallpaperService extends Service { /** * Notifies the engine that wallpaper colors changed significantly. - * This will trigger a {@link #onComputeWallpaperColors()} call. - * @hide + * This will trigger a {@link #onComputeColors()} call. */ - public void invalidateColors() { + public void notifyColorsChanged() { try { - mConnection.onWallpaperColorsChanged(onComputeWallpaperColors()); + mConnection.onWallpaperColorsChanged(onComputeColors()); } catch (RemoteException e) { Log.w(TAG, "Can't invalidate wallpaper colors because " + "wallpaper connection was lost", e); @@ -560,19 +559,18 @@ public abstract class WallpaperService extends Service { } /** - * Notifies the system about what colors the wallpaper is using. + * Called by the system when it needs to know what colors the wallpaper is using. * You might return null if no color information is available at the moment. In that case - * you might want to call {@link #invalidateColors()} in a near future. + * you might want to call {@link #notifyColorsChanged()} in a near future. * <p> - * The simplest way of creating A {@link android.app.WallpaperColors} object is by using + * The simplest way of creating a {@link android.app.WallpaperColors} object is by using * {@link android.app.WallpaperColors#fromBitmap(Bitmap)} or * {@link android.app.WallpaperColors#fromDrawable(Drawable)}, but you can also specify - * your main colors and dark text support explicitly using one of the constructors. + * your main colors by constructing a {@link android.app.WallpaperColors} object manually. * * @return Wallpaper colors. - * @hide */ - public @Nullable WallpaperColors onComputeWallpaperColors() { + public @Nullable WallpaperColors onComputeColors() { return null; } @@ -1212,7 +1210,7 @@ public abstract class WallpaperService extends Service { mEngine = engine; mActiveEngines.add(engine); engine.attach(this); - engine.invalidateColors(); + engine.notifyColorsChanged(); return; } case DO_DETACH: { diff --git a/core/java/android/util/RecurrenceRule.java b/core/java/android/util/RecurrenceRule.java new file mode 100644 index 000000000000..1fe638d6b76b --- /dev/null +++ b/core/java/android/util/RecurrenceRule.java @@ -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; + } +} diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 8e550dc1cb54..4041bcf7e3cb 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2599,5 +2599,16 @@ public interface WindowManager extends ViewManager { encoder.addProperty("type", type); encoder.addProperty("flags", flags); } + + /** + * @hide + * @return True if the layout parameters will cause the window to cover the full screen; + * false otherwise. + */ + public boolean isFullscreen() { + return x == 0 && y == 0 + && width == WindowManager.LayoutParams.MATCH_PARENT + && height == WindowManager.LayoutParams.MATCH_PARENT; + } } } diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index 3d8c85e684cb..3188d3005cae 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -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()); } } diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index e212c432558c..fa645f4d4c6a 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -315,7 +315,6 @@ message GlobalSettingsProto { SettingProto boot_count = 270; SettingProto safe_boot_disallowed = 271; SettingProto device_demo_mode = 272; - SettingProto retail_demo_mode_constants = 273; SettingProto database_downgrade_reason = 274; SettingProto contacts_database_wal_enabled = 275; SettingProto multi_sim_voice_call_subscription = 276; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c052e5145190..4a2ef3228d5e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -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" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8c26db43fc41..65c52792226b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4538,22 +4538,10 @@ <!-- The representation of a time duration when negative. An example is -1:14. This can be used with a countdown timer for example.--> <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string> - <!-- Title of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] --> - <string name="reset_retail_demo_mode_title">Reset device?</string> - <!-- Text of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] --> - <string name="reset_retail_demo_mode_text">Tap to reset device</string> <!-- Text of dialog shown when starting a demo user for the first time [CHAR LIMIT=40] --> <string name="demo_starting_message">Starting demo\u2026</string> <!-- Text of dialog shown when starting a new demo user in retail demo mode [CHAR LIMIT=40] --> <string name="demo_restarting_message">Resetting device\u2026</string> - <!-- Title of the dialog shown when user inactivity times out in retail demo mode [CHAR LIMIT=40] --> - <string name="demo_user_inactivity_timeout_title">Reset device?</string> - <!-- Warning message shown when user inactivity times out in retail demo mode [CHAR LIMIT=none] --> - <string name="demo_user_inactivity_timeout_countdown">You\u2019ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string> - <!-- Text of button to allow user to abort countdown and continue current session in retail demo mode [CHAR LIMIT=40] --> - <string name="demo_user_inactivity_timeout_left_button">Cancel</string> - <!-- Text of button to allow user to abort countdown and immediately start another session in retail demo mode [CHAR LIMIT=40] --> - <string name="demo_user_inactivity_timeout_right_button">Reset now</string> <!-- Accessibilty string added to a widget that has been suspended [CHAR LIMIT=20] --> <string name="suspended_widget_accessibility">Disabled <xliff:g id="label" example="Calendar">%1$s</xliff:g></string> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 949fd166c14c..e292c9dfbe67 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -304,7 +304,6 @@ public class SettingsBackupTest { Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT, Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, - Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, Settings.Global.SAFE_BOOT_DISALLOWED, Settings.Global.SAMPLING_PROFILER_MS, Settings.Global.SELINUX_STATUS, diff --git a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java new file mode 100644 index 000000000000..42b6048b533a --- /dev/null +++ b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java @@ -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); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java index c346898e2911..b01fc8541957 100644 --- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java +++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java @@ -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(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index b328933cd1c5..819ee3ee57ff 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -915,9 +915,6 @@ class SettingsProtoDumpUtil { Settings.Global.DEVICE_DEMO_MODE, GlobalSettingsProto.DEVICE_DEMO_MODE); dumpSetting(s, p, - Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, - GlobalSettingsProto.RETAIL_DEMO_MODE_CONSTANTS); - dumpSetting(s, p, Settings.Global.DATABASE_DOWNGRADE_REASON, GlobalSettingsProto.DATABASE_DOWNGRADE_REASON); dumpSetting(s, p, diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 38b2969265cb..6eea030ef0f3 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -273,6 +273,9 @@ <!-- Doze: the brightness value to use for the higher brightness AOD mode --> <integer name="config_doze_aod_brightness_high">27</integer> + <!-- Doze: the brightness value to use for the sunlight AOD mode --> + <integer name="config_doze_aod_brightness_sunlight">28</integer> + <!-- Doze: whether the double tap sensor reports 2D touch coordinates --> <bool name="doze_double_tap_reports_touch_coordinates">false</bool> diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java index 44cf003b3dcb..fe8373ffa127 100644 --- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java @@ -98,7 +98,7 @@ public class SysuiColorExtractor extends ColorExtractor { */ @Override public GradientColors getColors(int which) { - return getColors(which, TYPE_NORMAL); + return getColors(which, TYPE_DARK); } /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 28a45aae6892..ed4b131cd83f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -39,6 +39,7 @@ public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListen private final int mHighBrightness; private final int mLowBrightness; + private final int mSunlightBrightness; public DozeScreenBrightness(Context context, DozeMachine.Service service, SensorManager sensorManager, Sensor lightSensor, Handler handler) { @@ -52,6 +53,8 @@ public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListen R.integer.config_doze_aod_brightness_low); mHighBrightness = context.getResources().getInteger( R.integer.config_doze_aod_brightness_high); + mSunlightBrightness = context.getResources().getInteger( + R.integer.config_doze_aod_brightness_sunlight); } @Override @@ -83,9 +86,12 @@ public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListen } private int computeBrightness(int sensorValue) { - // The sensor reports 0 for off, 1 for low brightness and 2 for high brightness. - // We currently use DozeScreenState for screen off, so we treat off as low brightness. - if (sensorValue >= 2) { + // The sensor reports 0 for off, 1 for low brightness, 2 for high brightness, and 3 for + // sunlight. We currently use DozeScreenState for screen off, so we treat off as low + // brightness. + if (sensorValue >= 3) { + return mSunlightBrightness; + } else if (sensorValue == 2) { return mHighBrightness; } else { return mLowBrightness; diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 9b113d8463fd..ad177a7e849f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -25,8 +25,10 @@ import com.android.internal.telephony.TelephonyProperties; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.HardwareUiLayout; +import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; +import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.volume.VolumeDialogMotion.LogAccelerateInterpolator; import com.android.systemui.volume.VolumeDialogMotion.LogDecelerateInterpolator; @@ -65,6 +67,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import android.util.MathUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -112,6 +115,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn private static final String GLOBAL_ACTION_KEY_ASSIST = "assist"; private static final String GLOBAL_ACTION_KEY_RESTART = "restart"; + private static final float SHUTDOWN_SCRIM_ALPHA = 0.95f; + private final Context mContext; private final GlobalActionsManager mWindowManagerFuncs; private final AudioManager mAudioManager; @@ -1291,7 +1296,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn .alpha(1) .translationX(0) .setDuration(300) - .setInterpolator(new LogDecelerateInterpolator()) + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setUpdateListener(animation -> { int alpha = (int) ((Float) animation.getAnimatedValue() * ScrimController.GRADIENT_SCRIM_ALPHA * 255); @@ -1329,9 +1334,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn .setInterpolator(new LogAccelerateInterpolator()) .setUpdateListener(animation -> { float frac = animation.getAnimatedFraction(); - float alpha = frac *(ScrimController.GRADIENT_SCRIM_ALPHA_BUSY - - ScrimController.GRADIENT_SCRIM_ALPHA) - + ScrimController.GRADIENT_SCRIM_ALPHA; + float alpha = NotificationUtils.interpolate( + ScrimController.GRADIENT_SCRIM_ALPHA, SHUTDOWN_SCRIM_ALPHA, frac); mGradientDrawable.setAlpha((int) (alpha * 255)); }) .start(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 81ec6a7c72a9..4e728f68890a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -19,13 +19,14 @@ package com.android.systemui.qs.tiles; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Resources; +import android.os.SystemProperties; import android.service.quicksettings.Tile; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Switch; - import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; @@ -38,7 +39,6 @@ import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.qs.CellTileView; import com.android.systemui.qs.CellTileView.SignalIcon; import com.android.systemui.qs.QSHost; -import com.android.systemui.qs.SignalTileView; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.IconState; @@ -46,8 +46,17 @@ import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; /** Quick settings tile: Cellular **/ public class CellularTile extends QSTileImpl<SignalState> { - static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName( - "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity")); + private static final ComponentName CELLULAR_SETTING_COMPONENT = new ComponentName( + "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"); + private static final ComponentName DATA_PLAN_CELLULAR_COMPONENT = new ComponentName( + "com.android.settings", "com.android.settings.Settings$DataPlanUsageSummaryActivity"); + + private static final Intent CELLULAR_SETTINGS = + new Intent().setComponent(CELLULAR_SETTING_COMPONENT); + private static final Intent DATA_PLAN_CELLULAR_SETTINGS = + new Intent().setComponent(DATA_PLAN_CELLULAR_COMPONENT); + + private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan"; private final NetworkController mController; private final DataUsageController mDataController; @@ -90,7 +99,7 @@ public class CellularTile extends QSTileImpl<SignalState> { @Override public Intent getLongClickIntent() { - return CELLULAR_SETTINGS; + return getCellularSettingIntent(mContext); } @Override @@ -103,7 +112,9 @@ public class CellularTile extends QSTileImpl<SignalState> { if (mDataController.isMobileDataSupported()) { showDetail(true); } else { - mActivityStarter.postStartActivityDismissingKeyguard(CELLULAR_SETTINGS, 0); + mActivityStarter + .postStartActivityDismissingKeyguard(getCellularSettingIntent(mContext), + 0 /* delay */); } } @@ -240,7 +251,28 @@ public class CellularTile extends QSTileImpl<SignalState> { public void setMobileDataEnabled(boolean enabled) { mDetailAdapter.setMobileDataEnabled(enabled); } - }; + } + + static Intent getCellularSettingIntent(Context context) { + // TODO(b/62349208): We should replace feature flag check below with data plans + // availability check. If the data plans are available we display the data plans usage + // summary otherwise we display data usage summary without data plans. + boolean isDataPlanFeatureEnabled = + SystemProperties.getBoolean(ENABLE_SETTINGS_DATA_PLAN, false /* default */); + context.getPackageManager() + .setComponentEnabledSetting( + DATA_PLAN_CELLULAR_COMPONENT, + isDataPlanFeatureEnabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + context.getPackageManager() + .setComponentEnabledSetting( + CELLULAR_SETTING_COMPONENT, + isDataPlanFeatureEnabled ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED + : PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + return isDataPlanFeatureEnabled ? DATA_PLAN_CELLULAR_SETTINGS : CELLULAR_SETTINGS; + } private final class CellularDetailAdapter implements DetailAdapter { @@ -258,7 +290,7 @@ public class CellularTile extends QSTileImpl<SignalState> { @Override public Intent getSettingsIntent() { - return CELLULAR_SETTINGS; + return getCellularSettingIntent(mContext); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java index b7964512a2fa..8b62beb861ba 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java @@ -14,18 +14,16 @@ package com.android.systemui.qs.tiles; -import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.service.quicksettings.Tile; import android.widget.Switch; - -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.qs.QSHost; import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.DataSaverController; @@ -57,9 +55,8 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements @Override public Intent getLongClickIntent() { - return CellularTile.CELLULAR_SETTINGS; + return CellularTile.getCellularSettingIntent(mContext); } - @Override protected void handleClick() { if (mState.value @@ -73,12 +70,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements dialog.setTitle(com.android.internal.R.string.data_saver_enable_title); dialog.setMessage(com.android.internal.R.string.data_saver_description); dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - toggleDataSaver(); - } - }); + (OnClickListener) (dialogInterface, which) -> toggleDataSaver()); dialog.setNegativeButton(com.android.internal.R.string.cancel, null); dialog.setShowForAllUsers(true); dialog.show(); @@ -126,4 +118,4 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements public void onDataSaverChanged(boolean isDataSaving) { refreshState(isDataSaving); } -}
\ No newline at end of file +} diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 53190869513b..6167d85f33c7 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -4252,6 +4252,11 @@ message MetricsEvent { // OS: O MR FIELD_RANKED_POSITION = 1087; + // OPEN: Settings > Data plan usage + // CATEGORY: SETTINGS + // OS: O MR + DATA_PLAN_USAGE_SUMMARY = 1088; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/Android.mk b/services/Android.mk index 6a73d5f65351..0986e0a4aad4 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -34,7 +34,6 @@ services := \ net \ print \ restrictions \ - retaildemo \ usage \ usb \ voiceinteraction diff --git a/services/art-profile b/services/art-profile index bd6ed23fa993..140465a1c35e 100644 --- a/services/art-profile +++ b/services/art-profile @@ -11901,23 +11901,6 @@ PLcom/android/server/restrictions/RestrictionsManagerService$RestrictionsManager PLcom/android/server/restrictions/RestrictionsManagerService;->-wrap0(Lcom/android/server/restrictions/RestrictionsManagerService;Ljava/lang/String;)Landroid/os/IBinder; PLcom/android/server/restrictions/RestrictionsManagerService;-><init>(Landroid/content/Context;)V PLcom/android/server/restrictions/RestrictionsManagerService;->onStart()V -PLcom/android/server/retaildemo/RetailDemoModeService$1;-><init>(Lcom/android/server/retaildemo/RetailDemoModeService;)V -PLcom/android/server/retaildemo/RetailDemoModeService$1;->onUserActivity()V -PLcom/android/server/retaildemo/RetailDemoModeService$Injector;-><init>(Landroid/content/Context;)V -PLcom/android/server/retaildemo/RetailDemoModeService$Injector;->getContentResolver()Landroid/content/ContentResolver; -PLcom/android/server/retaildemo/RetailDemoModeService$Injector;->getContext()Landroid/content/Context; -PLcom/android/server/retaildemo/RetailDemoModeService$Injector;->publishLocalService(Lcom/android/server/retaildemo/RetailDemoModeService;Landroid/app/RetailDemoModeServiceInternal;)V -PLcom/android/server/retaildemo/RetailDemoModeService$MainHandler;-><init>(Lcom/android/server/retaildemo/RetailDemoModeService;Landroid/os/Looper;)V -PLcom/android/server/retaildemo/RetailDemoModeService$SettingsObserver;->-wrap0(Lcom/android/server/retaildemo/RetailDemoModeService$SettingsObserver;)V -PLcom/android/server/retaildemo/RetailDemoModeService$SettingsObserver;-><init>(Lcom/android/server/retaildemo/RetailDemoModeService;Landroid/os/Handler;)V -PLcom/android/server/retaildemo/RetailDemoModeService$SettingsObserver;->refreshTimeoutConstants()V -PLcom/android/server/retaildemo/RetailDemoModeService$SettingsObserver;->register()V -PLcom/android/server/retaildemo/RetailDemoModeService;->-get1(Lcom/android/server/retaildemo/RetailDemoModeService;)Lcom/android/server/retaildemo/RetailDemoModeService$Injector; -PLcom/android/server/retaildemo/RetailDemoModeService;->-wrap2(Lcom/android/server/retaildemo/RetailDemoModeService;Ljava/lang/Class;Ljava/lang/Object;)V -PLcom/android/server/retaildemo/RetailDemoModeService;-><init>(Landroid/content/Context;)V -PLcom/android/server/retaildemo/RetailDemoModeService;-><init>(Lcom/android/server/retaildemo/RetailDemoModeService$Injector;)V -PLcom/android/server/retaildemo/RetailDemoModeService;->onBootPhase(I)V -PLcom/android/server/retaildemo/RetailDemoModeService;->onStart()V PLcom/android/server/search/SearchManagerService$GlobalSearchProviderObserver;-><init>(Lcom/android/server/search/SearchManagerService;Landroid/content/ContentResolver;)V PLcom/android/server/search/SearchManagerService$Lifecycle$1;-><init>(Lcom/android/server/search/SearchManagerService$Lifecycle;I)V PLcom/android/server/search/SearchManagerService$Lifecycle$1;->run()V diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index a02802859ca7..41de97c8bcbb 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -698,6 +698,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { final SparseArray<Operation> mCurrentOperations = new SparseArray<Operation>(); final Object mCurrentOpLock = new Object(); final Random mTokenGenerator = new Random(); + final AtomicInteger mNextToken = new AtomicInteger(); final SparseArray<AdbParams> mAdbBackupRestoreConfirmations = new SparseArray<AdbParams>(); @@ -770,15 +771,13 @@ public class BackupManagerService implements BackupManagerServiceInterface { @GuardedBy("mQueueLock") ArrayList<FullBackupEntry> mFullBackupQueue; - // Utility: build a new random integer token + // Utility: build a new random integer token. The low bits are the ordinal of the + // operation for near-time uniqueness, and the upper bits are random for app- + // side unpredictability. @Override public int generateRandomIntegerToken() { - int token; - do { - synchronized (mTokenGenerator) { - token = mTokenGenerator.nextInt(); - } - } while (token < 0); + int token = mTokenGenerator.nextInt() & ~0xFF; + token |= (mNextToken.incrementAndGet() & 0xFF); return token; } diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 68f8c1bb182f..b516a91715d5 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -268,3 +268,16 @@ option java_package com.android.server # GestureLauncherService.java # --------------------------- 40100 camera_gesture_triggered (gesture_on_time|2|3), (sensor1_on_time|2|3), (sensor2_on_time|2|3), (event_extra|1|1) + +# --------------------------- +# timezone/RulesManagerService.java +# --------------------------- +51600 timezone_trigger_check (token|3) +51610 timezone_request_install (token|3) +51611 timezone_install_started (token|3) +51612 timezone_install_complete (token|3), (result|1) +51620 timezone_request_uninstall (token|3) +51621 timezone_uninstall_started (token|3) +51622 timezone_uninstall_complete (token|3), (result|1) +51630 timezone_request_nothing (token|3) +51631 timezone_nothing_complete (token|3) diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java index 048bef7b19f5..feddfe3a2169 100644 --- a/services/core/java/com/android/server/am/VrController.java +++ b/services/core/java/com/android/server/am/VrController.java @@ -163,6 +163,7 @@ final class VrController { ComponentName requestedPackage; ComponentName callingPackage; int userId; + int processId = -1; boolean changed = false; synchronized (mGlobalAmLock) { vrMode = record.requestedVrComponent != null; @@ -172,11 +173,15 @@ final class VrController { // Tell the VrController that a VR mode change is requested. changed = changeVrModeLocked(vrMode, record.app); + + if (record.app != null) { + processId = record.app.pid; + } } // Tell VrManager that a VR mode changed is requested, VrManager will handle // notifying all non-AM dependencies if needed. - vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage); + vrService.setVrMode(vrMode, requestedPackage, userId, processId, callingPackage); return changed; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 38f1c076727f..f70486a8b889 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -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,22 +2719,19 @@ 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); @@ -2658,14 +2739,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @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; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8e2097ae2609..d36d2f187e53 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5417,7 +5417,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // represent should be hidden or if we should hide the lockscreen. For attached app // windows we defer the decision to the window it is attached to. if (appWindow && attached == null) { - if (isFullscreen(attrs) && StackId.normallyFullscreenWindows(stackId)) { + if (attrs.isFullscreen() && StackId.normallyFullscreenWindows(stackId)) { if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; if (mTopFullscreenOpaqueOrDimmingWindowState == null) { @@ -5456,7 +5456,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // separately, because both the "real fullscreen" opaque window and the one for the docked // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null - && isFullscreen(attrs) && stackId == DOCKED_STACK_ID) { + && attrs.isFullscreen() && stackId == DOCKED_STACK_ID) { mTopDockedOpaqueWindowState = win; if (mTopDockedOpaqueOrDimmingWindowState == null) { mTopDockedOpaqueOrDimmingWindowState = win; @@ -5481,12 +5481,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private boolean isFullscreen(WindowManager.LayoutParams attrs) { - return attrs.x == 0 && attrs.y == 0 - && attrs.width == WindowManager.LayoutParams.MATCH_PARENT - && attrs.height == WindowManager.LayoutParams.MATCH_PARENT; - } - /** {@inheritDoc} */ @Override public int finishPostLayoutPolicyLw() { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index c68854286a19..0c72326095a6 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -53,6 +53,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -197,6 +198,9 @@ public final class PowerManagerService extends SystemService // System property indicating that the screen should remain off until an explicit user action private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent"; + // System Property indicating that retail demo mode is currently enabled. + private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled"; + // Possible reasons for shutting down for use in data/misc/reboot/last_shutdown_reason private static final String REASON_SHUTDOWN = "shutdown"; private static final String REASON_REBOOT = "reboot"; @@ -805,6 +809,9 @@ public final class PowerManagerService extends SystemService resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DOUBLE_TAP_TO_WAKE), false, mSettingsObserver, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.DEVICE_DEMO_MODE), + false, mSettingsObserver, UserHandle.USER_SYSTEM); IVrManager vrManager = (IVrManager) getBinderService(Context.VR_SERVICE); if (vrManager != null) { try { @@ -912,6 +919,11 @@ public final class PowerManagerService extends SystemService } } + final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ? "1" : "0"; + if (!retailDemoValue.equals(SystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED))) { + SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue); + } + final int oldScreenBrightnessSetting = getCurrentBrightnessSettingLocked(); mScreenBrightnessForVrSetting = Settings.System.getIntForUser(resolver, diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java index 3ffbb2d61fd5..11928b964ec5 100644 --- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java +++ b/services/core/java/com/android/server/timezone/IntentHelperImpl.java @@ -16,6 +16,8 @@ package com.android.server.timezone; +import com.android.server.EventLogTags; + import android.app.timezone.RulesUpdaterContract; import android.content.BroadcastReceiver; import android.content.Context; @@ -24,8 +26,6 @@ import android.content.IntentFilter; import android.os.PatternMatcher; import android.util.Slog; -import java.util.regex.Pattern; - /** * The bona fide implementation of {@link IntentHelper}. */ @@ -75,6 +75,7 @@ final class IntentHelperImpl implements IntentHelper { public void sendTriggerUpdateCheck(CheckToken checkToken) { RulesUpdaterContract.sendBroadcast( mContext, mUpdaterAppPackageName, checkToken.toByteArray()); + EventLogTags.writeTimezoneTriggerCheck(checkToken.toString()); } @Override diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java index d97ba2d0d78b..1c5aa600580a 100644 --- a/services/core/java/com/android/server/timezone/RulesManagerService.java +++ b/services/core/java/com/android/server/timezone/RulesManagerService.java @@ -17,6 +17,7 @@ package com.android.server.timezone; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.EventLogTags; import com.android.server.SystemService; import com.android.timezone.distro.DistroException; import com.android.timezone.distro.DistroVersion; @@ -56,8 +57,6 @@ import static android.app.timezone.RulesState.STAGED_OPERATION_NONE; import static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL; import static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN; -// TODO(nfuller) Add EventLog calls where useful in the system server. -// TODO(nfuller) Check logging best practices in the system server. // TODO(nfuller) Check error handling best practices in the system server. public final class RulesManagerService extends IRulesManager.Stub { @@ -203,6 +202,7 @@ public final class RulesManagerService extends IRulesManager.Stub { if (checkTokenBytes != null) { checkToken = createCheckTokenOrThrow(checkTokenBytes); } + EventLogTags.writeTimezoneRequestInstall(toStringOrNull(checkToken)); synchronized (this) { if (distroParcelFileDescriptor == null) { @@ -254,6 +254,8 @@ public final class RulesManagerService extends IRulesManager.Stub { @Override public void run() { + EventLogTags.writeTimezoneInstallStarted(toStringOrNull(mCheckToken)); + boolean success = false; // Adopt the ParcelFileDescriptor into this try-with-resources so it is closed // when we are done. @@ -266,6 +268,7 @@ public final class RulesManagerService extends IRulesManager.Stub { TimeZoneDistro distro = new TimeZoneDistro(is); int installerResult = mInstaller.stageInstallWithErrorCode(distro); int resultCode = mapInstallerResultToApiCode(installerResult); + EventLogTags.writeTimezoneInstallComplete(toStringOrNull(mCheckToken), resultCode); sendFinishedStatus(mCallback, resultCode); // All the installer failure modes are currently non-recoverable and won't be @@ -273,6 +276,8 @@ public final class RulesManagerService extends IRulesManager.Stub { success = true; } catch (Exception e) { Slog.w(TAG, "Failed to install distro.", e); + EventLogTags.writeTimezoneInstallComplete( + toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE); sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE); } finally { // Notify the package tracker that the operation is now complete. @@ -308,6 +313,7 @@ public final class RulesManagerService extends IRulesManager.Stub { if (checkTokenBytes != null) { checkToken = createCheckTokenOrThrow(checkTokenBytes); } + EventLogTags.writeTimezoneRequestUninstall(toStringOrNull(checkToken)); synchronized(this) { if (callback == null) { throw new NullPointerException("callback == null"); @@ -337,6 +343,7 @@ public final class RulesManagerService extends IRulesManager.Stub { @Override public void run() { + EventLogTags.writeTimezoneUninstallStarted(toStringOrNull(mCheckToken)); boolean success = false; try { success = mInstaller.stageUninstall(); @@ -344,8 +351,12 @@ public final class RulesManagerService extends IRulesManager.Stub { // against SUCCESS. More granular failures may be added in future. int resultCode = success ? Callback.SUCCESS : Callback.ERROR_UNKNOWN_FAILURE; + EventLogTags.writeTimezoneUninstallComplete( + toStringOrNull(mCheckToken), resultCode); sendFinishedStatus(mCallback, resultCode); } catch (Exception e) { + EventLogTags.writeTimezoneUninstallComplete( + toStringOrNull(mCheckToken), Callback.ERROR_UNKNOWN_FAILURE); Slog.w(TAG, "Failed to uninstall distro.", e); sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE); } finally { @@ -372,7 +383,9 @@ public final class RulesManagerService extends IRulesManager.Stub { if (checkTokenBytes != null) { checkToken = createCheckTokenOrThrow(checkTokenBytes); } + EventLogTags.writeTimezoneRequestNothing(toStringOrNull(checkToken)); mPackageTracker.recordCheckResult(checkToken, success); + EventLogTags.writeTimezoneNothingComplete(toStringOrNull(checkToken)); } @Override @@ -445,6 +458,7 @@ public final class RulesManagerService extends IRulesManager.Stub { pw.println("RulesManagerService state: " + toString()); pw.println("Active rules version (ICU, libcore): " + ICU.getTZDataVersion() + "," + ZoneInfoDB.getInstance().getVersion()); + pw.println("Distro state: " + rulesState.toString()); mPackageTracker.dump(pw); } @@ -491,4 +505,8 @@ public final class RulesManagerService extends IRulesManager.Stub { return "Unknown"; } } + + private static String toStringOrNull(Object obj) { + return obj == null ? null : obj.toString(); + } } diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java index 1f7564027166..bdd9de011186 100644 --- a/services/core/java/com/android/server/vr/VrManagerInternal.java +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -52,10 +52,11 @@ public abstract class VrManagerInternal { * @param enabled {@code true} to enable VR mode. * @param packageName The package name of the requested VrListenerService to bind. * @param userId the user requesting the VrListenerService component. + * @param processId the process the component is running in. * @param calling the component currently using VR mode, or null to leave unchanged. */ public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName, - int userId, @NonNull ComponentName calling); + int userId, int processId, @NonNull ComponentName calling); /** * Set whether the system has acquired a sleep token. diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index b10c9a3fd2ac..a6b8d94fb6b5 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -128,6 +128,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC private boolean mVrModeAllowed; private boolean mVrModeEnabled; private boolean mPersistentVrModeEnabled; + private boolean mRunning2dInVr; + private int mVrAppProcessId; private EnabledComponentsObserver mComponentObserver; private ManagedApplicationService mCurrentVrService; private ComponentName mDefaultVrService; @@ -178,7 +180,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC } consumeAndApplyPendingStateLocked(); if (mBootsToVr && !mVrModeEnabled) { - setVrMode(true, mDefaultVrService, 0, null); + setVrMode(true, mDefaultVrService, 0, -1, null); } } else { // Disable persistent mode when VR mode isn't allowed, allows an escape hatch to @@ -187,12 +189,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC // Set pending state to current state. mPendingState = (mVrModeEnabled && mCurrentVrService != null) - ? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(), - mCurrentVrService.getUserId(), mCurrentVrModeComponent) + ? new VrState(mVrModeEnabled, mRunning2dInVr, mCurrentVrService.getComponent(), + mCurrentVrService.getUserId(), mVrAppProcessId, mCurrentVrModeComponent) : null; // Unbind current VR service and do necessary callbacks. - updateCurrentVrServiceLocked(false, null, 0, null); + updateCurrentVrServiceLocked(false, false, null, 0, -1, null); } } } @@ -274,26 +276,33 @@ public class VrManagerService extends SystemService implements EnabledComponentC private static class VrState { final boolean enabled; + final boolean running2dInVr; final int userId; + final int processId; final ComponentName targetPackageName; final ComponentName callingPackage; final long timestamp; final boolean defaultPermissionsGranted; - VrState(boolean enabled, ComponentName targetPackageName, int userId, - ComponentName callingPackage) { + + VrState(boolean enabled, boolean running2dInVr, ComponentName targetPackageName, int userId, + int processId, ComponentName callingPackage) { this.enabled = enabled; + this.running2dInVr = running2dInVr; this.userId = userId; + this.processId = processId; this.targetPackageName = targetPackageName; this.callingPackage = callingPackage; this.defaultPermissionsGranted = false; this.timestamp = System.currentTimeMillis(); } - VrState(boolean enabled, ComponentName targetPackageName, int userId, - ComponentName callingPackage, boolean defaultPermissionsGranted) { + VrState(boolean enabled, boolean running2dInVr, ComponentName targetPackageName, int userId, + int processId, ComponentName callingPackage, boolean defaultPermissionsGranted) { this.enabled = enabled; + this.running2dInVr = running2dInVr; this.userId = userId; + this.processId = processId; this.targetPackageName = targetPackageName; this.callingPackage = callingPackage; this.defaultPermissionsGranted = defaultPermissionsGranted; @@ -394,8 +403,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC } // There is an active service, update it if needed - updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(), - mCurrentVrService.getUserId(), mCurrentVrModeComponent); + updateCurrentVrServiceLocked(mVrModeEnabled, mRunning2dInVr, + mCurrentVrService.getComponent(), mCurrentVrService.getUserId(), + mVrAppProcessId, mCurrentVrModeComponent); } } @@ -531,9 +541,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC */ private final class LocalService extends VrManagerInternal { @Override - public void setVrMode(boolean enabled, ComponentName packageName, int userId, + public void setVrMode(boolean enabled, ComponentName packageName, int userId, int processId, ComponentName callingPackage) { - VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage); + VrManagerService.this.setVrMode(enabled, packageName, userId, processId, callingPackage); } @Override @@ -710,14 +720,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC * Note: Must be called while holding {@code mLock}. * * @param enabled new state for VR mode. + * @param running2dInVr true if we have a top-level 2D intent. * @param component new component to be bound as a VR listener. * @param userId user owning the component to be bound. - * @param calling the component currently using VR mode. + * @param processId the process hosting the activity specified by calling. + * @param calling the component currently using VR mode or a 2D intent. * * @return {@code true} if the component/user combination specified is valid. */ - private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component, - int userId, ComponentName calling) { + private boolean updateCurrentVrServiceLocked(boolean enabled, boolean running2dInVr, + @NonNull ComponentName component, int userId, int processId, ComponentName calling) { boolean sendUpdatedCaller = false; final long identity = Binder.clearCallingIdentity(); @@ -777,6 +789,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC sendUpdatedCaller = true; } mCurrentVrModeComponent = calling; + mRunning2dInVr = running2dInVr; + mVrAppProcessId = processId; if (mCurrentVrModeUser != userId) { mCurrentVrModeUser = userId; @@ -794,11 +808,13 @@ public class VrManagerService extends SystemService implements EnabledComponentC if (mCurrentVrService != null && sendUpdatedCaller) { final ComponentName c = mCurrentVrModeComponent; + final boolean b = running2dInVr; + final int pid = processId; mCurrentVrService.sendEvent(new PendingEvent() { @Override public void runEvent(IInterface service) throws RemoteException { IVrListener l = (IVrListener) service; - l.focusedActivityChanged(c); + l.focusedActivityChanged(c, b, pid); } }); } @@ -1001,20 +1017,20 @@ public class VrManagerService extends SystemService implements EnabledComponentC */ private void consumeAndApplyPendingStateLocked(boolean disconnectIfNoPendingState) { if (mPendingState != null) { - updateCurrentVrServiceLocked(mPendingState.enabled, - mPendingState.targetPackageName, mPendingState.userId, + updateCurrentVrServiceLocked(mPendingState.enabled, mPendingState.running2dInVr, + mPendingState.targetPackageName, mPendingState.userId, mPendingState.processId, mPendingState.callingPackage); mPendingState = null; } else if (disconnectIfNoPendingState) { - updateCurrentVrServiceLocked(false, null, 0, null); + updateCurrentVrServiceLocked(false, false, null, 0, -1, null); } } private void logStateLocked() { ComponentName currentBoundService = (mCurrentVrService == null) ? null : mCurrentVrService.getComponent(); - VrState current = new VrState(mVrModeEnabled, currentBoundService, mCurrentVrModeUser, - mCurrentVrModeComponent, mWasDefaultGranted); + VrState current = new VrState(mVrModeEnabled, mRunning2dInVr, currentBoundService, + mCurrentVrModeUser, mVrAppProcessId, mCurrentVrModeComponent, mWasDefaultGranted); if (mLoggingDeque.size() == EVENT_LOG_SIZE) { mLoggingDeque.removeFirst(); } @@ -1058,27 +1074,24 @@ public class VrManagerService extends SystemService implements EnabledComponentC * Implementation of VrManagerInternal calls. These are callable from system services. */ private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName, - int userId, @NonNull ComponentName callingPackage) { + int userId, int processId, @NonNull ComponentName callingPackage) { synchronized (mLock) { VrState pending; ComponentName targetListener; - ComponentName foregroundVrComponent; // If the device is in persistent VR mode, then calls to disable VR mode are ignored, // and the system default VR listener is used. boolean targetEnabledState = enabled || mPersistentVrModeEnabled; - if (!enabled && mPersistentVrModeEnabled) { + boolean running2dInVr = !enabled && mPersistentVrModeEnabled; + if (running2dInVr) { targetListener = mDefaultVrService; - - // Current foreground component isn't a VR one (in 2D app case) - foregroundVrComponent = null; } else { targetListener = targetPackageName; - foregroundVrComponent = callingPackage; } - pending = new VrState( - targetEnabledState, targetListener, userId, foregroundVrComponent); + + pending = new VrState(targetEnabledState, running2dInVr, targetListener, + userId, processId, callingPackage); if (!mVrModeAllowed) { // We're not allowed to be in VR mode. Make this state pending. This will be @@ -1103,8 +1116,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC mPendingState = null; } - updateCurrentVrServiceLocked( - targetEnabledState, targetListener, userId, foregroundVrComponent); + updateCurrentVrServiceLocked(targetEnabledState, running2dInVr, targetListener, + userId, processId, callingPackage); } } @@ -1113,7 +1126,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC setPersistentModeAndNotifyListenersLocked(enabled); // Disabling persistent mode when not showing a VR should disable the overall vr mode. if (!enabled && mCurrentVrModeComponent == null) { - setVrMode(false, null, 0, null); + setVrMode(false, null, 0, -1, null); } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 05f4626259d7..a37b2e56b0d0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2992,14 +2992,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Don't include wallpaper in bounds calculation if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) { if (includeDecor) { - final TaskStack stack = w.getStack(); - if (stack != null) { - stack.getBounds(frame); - } + final Task task = w.getTask(); + if (task != null) { + task.getBounds(frame); + } else { - // We want to screenshot with the exact bounds of the surface of the app. Thus, - // intersect it with the frame. - frame.intersect(w.mFrame); + // No task bounds? Too bad! Ain't no screenshot then. + return true; + } } else { final Rect wf = w.mFrame; final Rect cr = w.mContentInsets; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cc3b146e8e0d..e5055e92828e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -624,6 +624,17 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU return token != null ? token.findMainWindow() : null; } + AppWindowToken getTopFullscreenAppToken() { + for (int i = mChildren.size() - 1; i >= 0; i--) { + final AppWindowToken token = mChildren.get(i); + final WindowState win = token.findMainWindow(); + if (win != null && win.mAttrs.isFullscreen()) { + return token; + } + } + return null; + } + AppWindowToken getTopVisibleAppToken() { for (int i = mChildren.size() - 1; i >= 0; i--) { final AppWindowToken token = mChildren.get(i); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 802f9edc92dc..1bece6903eac 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -150,14 +150,27 @@ class TaskSnapshotSurface implements StartingSurface { final int currentOrientation; synchronized (service.mWindowMap) { final WindowState mainWindow = token.findMainWindow(); - if (mainWindow == null) { + final Task task = token.getTask(); + if (task == null) { + Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for token=" + + token); + return null; + } + final AppWindowToken topFullscreenToken = token.getTask().getTopFullscreenAppToken(); + if (topFullscreenToken == null) { + Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task=" + + task); + return null; + } + final WindowState topFullscreenWindow = topFullscreenToken.findMainWindow(); + if (mainWindow == null || topFullscreenWindow == null) { Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token=" + token); return null; } - sysUiVis = mainWindow.getSystemUiVisibility(); - windowFlags = mainWindow.getAttrs().flags; - windowPrivateFlags = mainWindow.getAttrs().privateFlags; + sysUiVis = topFullscreenWindow.getSystemUiVisibility(); + windowFlags = topFullscreenWindow.getAttrs().flags; + windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags; layoutParams.dimAmount = mainWindow.getAttrs().dimAmount; layoutParams.type = TYPE_APPLICATION_STARTING; @@ -170,22 +183,17 @@ class TaskSnapshotSurface implements StartingSurface { layoutParams.width = LayoutParams.MATCH_PARENT; layoutParams.height = LayoutParams.MATCH_PARENT; layoutParams.systemUiVisibility = sysUiVis; - final Task task = token.getTask(); - if (task != null) { - layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId)); - - final TaskDescription taskDescription = task.getTaskDescription(); - if (taskDescription != null) { - backgroundColor = taskDescription.getBackgroundColor(); - statusBarColor = taskDescription.getStatusBarColor(); - navigationBarColor = taskDescription.getNavigationBarColor(); - } - taskBounds = new Rect(); - task.getBounds(taskBounds); - } else { - taskBounds = null; + layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId)); + + final TaskDescription taskDescription = task.getTaskDescription(); + if (taskDescription != null) { + backgroundColor = taskDescription.getBackgroundColor(); + statusBarColor = taskDescription.getStatusBarColor(); + navigationBarColor = taskDescription.getNavigationBarColor(); } - currentOrientation = mainWindow.getConfiguration().orientation; + taskBounds = new Rect(); + task.getBounds(taskBounds); + currentOrientation = topFullscreenWindow.getConfiguration().orientation; } try { final int res = session.addToDisplay(window, window.mSeq, layoutParams, diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 85747287cf93..3757b7d0c53d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -99,7 +99,6 @@ import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import com.android.server.broadcastradio.BroadcastRadioService; import com.android.server.restrictions.RestrictionsManagerService; -import com.android.server.retaildemo.RetailDemoModeService; import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; import com.android.server.soundtrigger.SoundTriggerService; @@ -1536,10 +1535,6 @@ public final class SystemServer { mmsService = mSystemServiceManager.startService(MmsServiceBroker.class); traceEnd(); - traceBeginAndSlog("StartRetailDemoModeService"); - mSystemServiceManager.startService(RetailDemoModeService.class); - traceEnd(); - if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOFILL)) { traceBeginAndSlog("StartAutoFillService"); mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS); diff --git a/services/retaildemo/Android.mk b/services/retaildemo/Android.mk deleted file mode 100644 index 670c6bfa1e6a..000000000000 --- a/services/retaildemo/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := services.retaildemo - -LOCAL_SRC_FILES += \ - $(call all-java-files-under,java) - -LOCAL_JAVA_LIBRARIES := services.core - -include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java deleted file mode 100644 index 90c58d0279a7..000000000000 --- a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.retaildemo; - -import android.app.AppGlobals; -import android.app.PackageInstallObserver; -import android.content.Context; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.Environment; -import android.os.RemoteException; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.ArrayMap; -import android.util.Log; -import android.util.Slog; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; - -/** - * Helper class for installing preloaded APKs - */ -class PreloadAppsInstaller { - private static final String SYSTEM_SERVER_PACKAGE_NAME = "android"; - private static String TAG = PreloadAppsInstaller.class.getSimpleName(); - private static final String PRELOAD_APK_EXT = ".apk.preload"; - private static boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private final IPackageManager mPackageManager; - private final File preloadsAppsDirectory; - private final Context mContext; - - private final Map<String, String> mApkToPackageMap; - - PreloadAppsInstaller(Context context) { - this(context, AppGlobals.getPackageManager(), Environment.getDataPreloadsAppsDirectory()); - } - - @VisibleForTesting - PreloadAppsInstaller(Context context, IPackageManager packageManager, File preloadsAppsDirectory) { - mContext = context; - mPackageManager = packageManager; - mApkToPackageMap = Collections.synchronizedMap(new ArrayMap<>()); - this.preloadsAppsDirectory = preloadsAppsDirectory; - } - - void installApps(int userId) { - File[] files = preloadsAppsDirectory.listFiles(); - AppInstallCounter counter = new AppInstallCounter(mContext, userId); - if (ArrayUtils.isEmpty(files)) { - counter.setExpectedAppsCount(0); - return; - } - int expectedCount = 0; - for (File file : files) { - String apkName = file.getName(); - if (apkName.endsWith(PRELOAD_APK_EXT) && file.isFile()) { - String packageName = mApkToPackageMap.get(apkName); - if (packageName != null) { - try { - expectedCount++; - installExistingPackage(packageName, userId, counter); - } catch (Exception e) { - Slog.e(TAG, "Failed to install existing package " + packageName, e); - } - } else { - try { - installPackage(file, userId, counter); - expectedCount++; - } catch (Exception e) { - Slog.e(TAG, "Failed to install package from " + file, e); - } - } - } - } - counter.setExpectedAppsCount(expectedCount); - } - - private void installExistingPackage(String packageName, int userId, - AppInstallCounter counter) { - if (DEBUG) { - Log.d(TAG, "installExistingPackage " + packageName + " u" + userId); - } - try { - mPackageManager.installExistingPackageAsUser(packageName, userId, - 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } finally { - counter.appInstallFinished(); - } - } - - private void installPackage(File file, final int userId, AppInstallCounter counter) - throws IOException, RemoteException { - final String apkName = file.getName(); - if (DEBUG) { - Log.d(TAG, "installPackage " + apkName + " u" + userId); - } - mPackageManager.installPackageAsUser(file.getPath(), new PackageInstallObserver() { - @Override - public void onPackageInstalled(String basePackageName, int returnCode, String msg, - Bundle extras) { - if (DEBUG) { - Log.d(TAG, "Package " + basePackageName + " installed u" + userId - + " returnCode: " + returnCode + " msg: " + msg); - } - // Don't notify the counter for now, we'll do it in installExistingPackage - if (returnCode == PackageManager.INSTALL_SUCCEEDED) { - mApkToPackageMap.put(apkName, basePackageName); - // Install on user 0 so that the package is cached when demo user is re-created - installExistingPackage(basePackageName, UserHandle.USER_SYSTEM, counter); - } else if (returnCode == PackageManager.INSTALL_FAILED_ALREADY_EXISTS) { - // This can only happen in first session after a reboot - if (!mApkToPackageMap.containsKey(apkName)) { - mApkToPackageMap.put(apkName, basePackageName); - } - installExistingPackage(basePackageName, userId, counter); - } else { - Log.e(TAG, "Package " + basePackageName + " cannot be installed from " - + apkName + ": " + msg + " (returnCode " + returnCode + ")"); - counter.appInstallFinished(); - } - } - }.getBinder(), 0, SYSTEM_SERVER_PACKAGE_NAME, userId); - } - - private static class AppInstallCounter { - private int expectedCount = -1; // -1 means expectedCount not set - private int finishedCount; - private final Context mContext; - private final int userId; - - AppInstallCounter(Context context, int userId) { - mContext = context; - this.userId = userId; - } - - synchronized void appInstallFinished() { - this.finishedCount++; - checkIfAllFinished(); - } - - synchronized void setExpectedAppsCount(int expectedCount) { - this.expectedCount = expectedCount; - checkIfAllFinished(); - } - - private void checkIfAllFinished() { - if (expectedCount == finishedCount) { - Log.i(TAG, "All preloads finished installing for user " + userId); - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.DEMO_USER_SETUP_COMPLETE, "1", userId); - } - } - } -} diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java deleted file mode 100644 index 711d4d9d8a91..000000000000 --- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.retaildemo; - -import android.Manifest; -import android.app.ActivityManager; -import android.app.ActivityManagerInternal; -import android.app.AppGlobals; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.RetailDemoModeServiceInternal; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.UserInfo; -import android.content.res.Configuration; -import android.database.ContentObserver; -import android.hardware.camera2.CameraAccessException; -import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraManager; -import android.media.AudioManager; -import android.media.AudioSystem; -import android.net.Uri; -import android.net.wifi.WifiManager; -import android.os.Environment; -import android.os.FileUtils; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.CallLog; -import android.provider.MediaStore; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.KeyValueListParser; -import android.util.Slog; - -import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; -import com.android.internal.notification.SystemNotificationChannels; -import com.android.internal.os.BackgroundThread; -import com.android.internal.R; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.widget.LockPatternUtils; -import com.android.server.LocalServices; -import com.android.server.PreloadsFileCacheExpirationJobService; -import com.android.server.ServiceThread; -import com.android.server.SystemService; -import com.android.server.am.ActivityManagerService; -import com.android.server.retaildemo.UserInactivityCountdownDialog.OnCountDownExpiredListener; - -import java.io.File; -import java.util.ArrayList; - -public class RetailDemoModeService extends SystemService { - private static final boolean DEBUG = false; - - private static final String TAG = RetailDemoModeService.class.getSimpleName(); - private static final String DEMO_USER_NAME = "Demo"; - private static final String ACTION_RESET_DEMO = - "com.android.server.retaildemo.ACTION_RESET_DEMO"; - @VisibleForTesting - static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled"; - - private static final int MSG_TURN_SCREEN_ON = 0; - private static final int MSG_INACTIVITY_TIME_OUT = 1; - private static final int MSG_START_NEW_SESSION = 2; - - private static final long SCREEN_WAKEUP_DELAY = 2500; - private static final long USER_INACTIVITY_TIMEOUT_MIN = 10000; - private static final long USER_INACTIVITY_TIMEOUT_DEFAULT = 90000; - private static final long WARNING_DIALOG_TIMEOUT_DEFAULT = 0; - private static final long MILLIS_PER_SECOND = 1000; - - @VisibleForTesting - static final int[] VOLUME_STREAMS_TO_MUTE = { - AudioSystem.STREAM_RING, - AudioSystem.STREAM_MUSIC - }; - - // Tron Vars - private static final String DEMO_SESSION_COUNT = "retail_demo_session_count"; - private static final String DEMO_SESSION_DURATION = "retail_demo_session_duration"; - - boolean mDeviceInDemoMode; - boolean mIsCarrierDemoMode; - int mCurrentUserId = UserHandle.USER_SYSTEM; - long mUserInactivityTimeout; - long mWarningDialogTimeout; - private Injector mInjector; - Handler mHandler; - private ServiceThread mHandlerThread; - private String[] mCameraIdsWithFlash; - private PreloadAppsInstaller mPreloadAppsInstaller; - - final Object mActivityLock = new Object(); - // Whether the newly created demo user has interacted with the screen yet - @GuardedBy("mActivityLock") - boolean mUserUntouched; - @GuardedBy("mActivityLock") - long mFirstUserActivityTime; - @GuardedBy("mActivityLock") - long mLastUserActivityTime; - - private boolean mSafeBootRestrictionInitialState; - private int mPackageVerifierEnableInitialState; - - private IntentReceiver mBroadcastReceiver = null; - - private final class IntentReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (!mDeviceInDemoMode) { - return; - } - final String action = intent.getAction(); - switch (action) { - case Intent.ACTION_SCREEN_OFF: - mHandler.removeMessages(MSG_TURN_SCREEN_ON); - mHandler.sendEmptyMessageDelayed(MSG_TURN_SCREEN_ON, SCREEN_WAKEUP_DELAY); - break; - case ACTION_RESET_DEMO: - mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); - break; - } - } - }; - - final class MainHandler extends Handler { - - MainHandler(Looper looper) { - super(looper, null, true); - } - - @Override - public void handleMessage(Message msg) { - if (!mDeviceInDemoMode) { - return; - } - switch (msg.what) { - case MSG_TURN_SCREEN_ON: - if (mInjector.isWakeLockHeld()) { - mInjector.releaseWakeLock(); - } - mInjector.acquireWakeLock(); - break; - case MSG_INACTIVITY_TIME_OUT: - if (!mIsCarrierDemoMode && isDemoLauncherDisabled()) { - Slog.i(TAG, "User inactivity timeout reached"); - showInactivityCountdownDialog(); - } - break; - case MSG_START_NEW_SESSION: - if (DEBUG) { - Slog.d(TAG, "Switching to a new demo user"); - } - removeMessages(MSG_START_NEW_SESSION); - removeMessages(MSG_INACTIVITY_TIME_OUT); - if (!mIsCarrierDemoMode && mCurrentUserId != UserHandle.USER_SYSTEM) { - logSessionDuration(); - } - - final UserManager um = mInjector.getUserManager(); - UserInfo demoUser = null; - if (mIsCarrierDemoMode) { - // Re-use the existing demo user in carrier demo mode. - for (UserInfo user : um.getUsers()) { - if (user.isDemo()) { - demoUser = user; - break; - } - } - } - - if (demoUser == null) { - // User in carrier demo mode should survive reboots. - final int flags = UserInfo.FLAG_DEMO - | (mIsCarrierDemoMode ? 0 : UserInfo.FLAG_EPHEMERAL); - demoUser = um.createUser(DEMO_USER_NAME, flags); - } - - if (demoUser != null && mCurrentUserId != demoUser.id) { - setupDemoUser(demoUser); - mInjector.switchUser(demoUser.id); - } - break; - } - } - } - - @VisibleForTesting - class SettingsObserver extends ContentObserver { - - private final static String KEY_USER_INACTIVITY_TIMEOUT = "user_inactivity_timeout_ms"; - private final static String KEY_WARNING_DIALOG_TIMEOUT = "warning_dialog_timeout_ms"; - - private final Uri mDeviceDemoModeUri = Settings.Global - .getUriFor(Settings.Global.DEVICE_DEMO_MODE); - private final Uri mDeviceProvisionedUri = Settings.Global - .getUriFor(Settings.Global.DEVICE_PROVISIONED); - private final Uri mRetailDemoConstantsUri = Settings.Global - .getUriFor(Settings.Global.RETAIL_DEMO_MODE_CONSTANTS); - - private final KeyValueListParser mParser = new KeyValueListParser(','); - - public SettingsObserver(Handler handler) { - super(handler); - } - - public void register() { - final ContentResolver cr = mInjector.getContentResolver(); - cr.registerContentObserver(mDeviceDemoModeUri, false, this, UserHandle.USER_SYSTEM); - cr.registerContentObserver(mDeviceProvisionedUri, false, this, UserHandle.USER_SYSTEM); - cr.registerContentObserver(mRetailDemoConstantsUri, false, this, - UserHandle.USER_SYSTEM); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - if (mRetailDemoConstantsUri.equals(uri)) { - refreshTimeoutConstants(); - return; - } - - // If device is provisioned and left demo mode - run the cleanup in demo folder - if (isDeviceProvisioned()) { - if (UserManager.isDeviceInDemoMode(getContext())) { - startDemoMode(); - } else { - mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0"); - - // Run on the bg thread to not block the fg thread - BackgroundThread.getHandler().post(() -> { - if (!deletePreloadsFolderContents()) { - Slog.w(TAG, "Failed to delete preloads folder contents"); - } - PreloadsFileCacheExpirationJobService.schedule(mInjector.getContext()); - }); - - stopDemoMode(); - - if (mInjector.isWakeLockHeld()) { - mInjector.releaseWakeLock(); - } - } - } - } - - private void refreshTimeoutConstants() { - try { - mParser.setString(Settings.Global.getString(mInjector.getContentResolver(), - Settings.Global.RETAIL_DEMO_MODE_CONSTANTS)); - } catch (IllegalArgumentException exc) { - Slog.e(TAG, "Invalid string passed to KeyValueListParser"); - // Consuming the exception to fall back to default values. - } - mWarningDialogTimeout = mParser.getLong(KEY_WARNING_DIALOG_TIMEOUT, - WARNING_DIALOG_TIMEOUT_DEFAULT); - mUserInactivityTimeout = mParser.getLong(KEY_USER_INACTIVITY_TIMEOUT, - USER_INACTIVITY_TIMEOUT_DEFAULT); - mUserInactivityTimeout = Math.max(mUserInactivityTimeout, USER_INACTIVITY_TIMEOUT_MIN); - } - } - - private void showInactivityCountdownDialog() { - UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(), - mWarningDialogTimeout, MILLIS_PER_SECOND); - dialog.setNegativeButtonClickListener(null); - dialog.setPositiveButtonClickListener(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); - } - }); - dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() { - @Override - public void onCountDownExpired() { - mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); - } - }); - dialog.show(); - } - - public RetailDemoModeService(Context context) { - this(new Injector(context)); - } - - @VisibleForTesting - RetailDemoModeService(Injector injector) { - super(injector.getContext()); - - mInjector = injector; - synchronized (mActivityLock) { - mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis(); - } - } - - boolean isDemoLauncherDisabled() { - int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - try { - final IPackageManager iPm = mInjector.getIPackageManager(); - final String demoLauncherComponent = - getContext().getString(R.string.config_demoModeLauncherComponent); - enabledState = iPm.getComponentEnabledSetting( - ComponentName.unflattenFromString(demoLauncherComponent), mCurrentUserId); - } catch (RemoteException re) { - Slog.e(TAG, "Error retrieving demo launcher enabled setting", re); - } - return enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED; - } - - private void setupDemoUser(UserInfo userInfo) { - final UserManager um = mInjector.getUserManager(); - final UserHandle user = UserHandle.of(userInfo.id); - um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user); - um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user); - um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user); - um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user); - um.setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user); - um.setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user); - // Set this to false because the default is true on user creation - um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user); - // Disallow rebooting in safe mode - controlled by user 0 - um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM); - if (mIsCarrierDemoMode) { - // Enable SMS in carrier demo mode. - um.setUserRestriction(UserManager.DISALLOW_SMS, false, user); - } - - Settings.Secure.putIntForUser(mInjector.getContentResolver(), - Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id); - Settings.Global.putInt(mInjector.getContentResolver(), - Settings.Global.PACKAGE_VERIFIER_ENABLE, 0); - - grantRuntimePermissionToCamera(user); - clearPrimaryCallLog(); - - if (!mIsCarrierDemoMode) { - // Enable demo launcher. - final String demoLauncher = getContext().getString( - R.string.config_demoModeLauncherComponent); - if (!TextUtils.isEmpty(demoLauncher)) { - final ComponentName componentToEnable = - ComponentName.unflattenFromString(demoLauncher); - final String packageName = componentToEnable.getPackageName(); - try { - final IPackageManager iPm = AppGlobals.getPackageManager(); - iPm.setComponentEnabledSetting(componentToEnable, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id); - iPm.setApplicationEnabledSetting(packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null); - } catch (RemoteException re) { - // Internal, shouldn't happen - } - } - } else { - // Set the carrier demo mode setting for the demo user. - final String carrierDemoModeSetting = getContext().getString( - R.string.config_carrierDemoModeSetting); - Settings.Secure.putIntForUser(getContext().getContentResolver(), - carrierDemoModeSetting, 1, userInfo.id); - - // Enable packages for carrier demo mode. - final String packageList = getContext().getString( - R.string.config_carrierDemoModePackages); - final String[] packageNames = packageList == null ? new String[0] - : TextUtils.split(packageList, ","); - final IPackageManager iPm = AppGlobals.getPackageManager(); - for (String packageName : packageNames) { - try { - iPm.setApplicationEnabledSetting(packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userInfo.id, null); - } catch (RemoteException re) { - Slog.e(TAG, "Error enabling application: " + packageName, re); - } - } - } - } - - private void grantRuntimePermissionToCamera(UserHandle user) { - final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - final PackageManager pm = mInjector.getPackageManager(); - final ResolveInfo handler = pm.resolveActivityAsUser(cameraIntent, - PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - user.getIdentifier()); - if (handler == null || handler.activityInfo == null) { - return; - } - try { - pm.grantRuntimePermission(handler.activityInfo.packageName, - Manifest.permission.ACCESS_FINE_LOCATION, user); - } catch (Exception e) { - // Ignore - } - } - - private void clearPrimaryCallLog() { - final ContentResolver resolver = mInjector.getContentResolver(); - - // Deleting primary user call log so that it doesn't get copied to the new demo user - final Uri uri = CallLog.Calls.CONTENT_URI; - try { - resolver.delete(uri, null, null); - } catch (Exception e) { - Slog.w(TAG, "Deleting call log failed: " + e); - } - } - - void logSessionDuration() { - final int sessionDuration; - synchronized (mActivityLock) { - sessionDuration = (int) ((mLastUserActivityTime - mFirstUserActivityTime) / 1000); - } - mInjector.logSessionDuration(sessionDuration); - } - - private boolean isDeviceProvisioned() { - return Settings.Global.getInt( - mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; - } - - /** - * Deletes contents of {@link Environment#getDataPreloadsDirectory()}, - * but leave {@link Environment#getDataPreloadsFileCacheDirectory()} - * @return true if contents was sucessfully deleted - */ - private boolean deletePreloadsFolderContents() { - final File dir = mInjector.getDataPreloadsDirectory(); - final File[] files = FileUtils.listFilesOrEmpty(dir); - final File fileCacheDirectory = mInjector.getDataPreloadsFileCacheDirectory(); - Slog.i(TAG, "Deleting contents of " + dir); - boolean success = true; - for (File file : files) { - if (file.isFile()) { - if (!file.delete()) { - success = false; - Slog.w(TAG, "Cannot delete file " + file); - } - } else { - // Do not remove file_cache dir - if (!file.equals(fileCacheDirectory)) { - if (!FileUtils.deleteContentsAndDir(file)) { - success = false; - Slog.w(TAG, "Cannot delete dir and its content " + file); - } - } else { - Slog.i(TAG, "Skipping directory with file cache " + file); - } - } - } - return success; - } - - private void registerBroadcastReceiver() { - if (mBroadcastReceiver != null) { - return; - } - - final IntentFilter filter = new IntentFilter(); - if (!mIsCarrierDemoMode) { - filter.addAction(Intent.ACTION_SCREEN_OFF); - } - filter.addAction(ACTION_RESET_DEMO); - mBroadcastReceiver = new IntentReceiver(); - getContext().registerReceiver(mBroadcastReceiver, filter); - } - - private void unregisterBroadcastReceiver() { - if (mBroadcastReceiver != null) { - getContext().unregisterReceiver(mBroadcastReceiver); - mBroadcastReceiver = null; - } - } - - private String[] getCameraIdsWithFlash() { - ArrayList<String> cameraIdsList = new ArrayList<String>(); - final CameraManager cm = mInjector.getCameraManager(); - if (cm != null) { - try { - for (String cameraId : cm.getCameraIdList()) { - CameraCharacteristics c = cm.getCameraCharacteristics(cameraId); - if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) { - cameraIdsList.add(cameraId); - } - } - } catch (CameraAccessException e) { - Slog.e(TAG, "Unable to access camera while getting camera id list", e); - } - } - return cameraIdsList.toArray(new String[cameraIdsList.size()]); - } - - private void muteVolumeStreams() { - for (int stream : VOLUME_STREAMS_TO_MUTE) { - mInjector.getAudioManager().setStreamVolume(stream, - mInjector.getAudioManager().getStreamMinVolume(stream), 0); - } - } - - private void startDemoMode() { - mDeviceInDemoMode = true; - - mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller(); - mInjector.initializeWakeLock(); - if (mCameraIdsWithFlash == null) { - mCameraIdsWithFlash = getCameraIdsWithFlash(); - } - registerBroadcastReceiver(); - - final String carrierDemoModeSetting = - getContext().getString(R.string.config_carrierDemoModeSetting); - mIsCarrierDemoMode = !TextUtils.isEmpty(carrierDemoModeSetting) - && (Settings.Secure.getInt(getContext().getContentResolver(), - carrierDemoModeSetting, 0) == 1); - - mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1"); - mHandler.sendEmptyMessage(MSG_START_NEW_SESSION); - - mSafeBootRestrictionInitialState = mInjector.getUserManager().hasUserRestriction( - UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM); - mPackageVerifierEnableInitialState = Settings.Global.getInt(mInjector.getContentResolver(), - Settings.Global.PACKAGE_VERIFIER_ENABLE, 1); - } - - private void stopDemoMode() { - mPreloadAppsInstaller = null; - mCameraIdsWithFlash = null; - mInjector.destroyWakeLock(); - unregisterBroadcastReceiver(); - - if (mDeviceInDemoMode) { - mInjector.getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, - mSafeBootRestrictionInitialState, UserHandle.SYSTEM); - Settings.Global.putInt(mInjector.getContentResolver(), - Settings.Global.PACKAGE_VERIFIER_ENABLE, - mPackageVerifierEnableInitialState); - } - - mDeviceInDemoMode = false; - mIsCarrierDemoMode = false; - } - - @Override - public void onStart() { - if (DEBUG) { - Slog.d(TAG, "Service starting up"); - } - mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, - false); - mHandlerThread.start(); - mHandler = new MainHandler(mHandlerThread.getLooper()); - mInjector.publishLocalService(this, mLocalService); - } - - @Override - public void onBootPhase(int bootPhase) { - switch (bootPhase) { - case PHASE_THIRD_PARTY_APPS_CAN_START: - final SettingsObserver settingsObserver = new SettingsObserver(mHandler); - settingsObserver.register(); - settingsObserver.refreshTimeoutConstants(); - break; - case PHASE_BOOT_COMPLETED: - if (UserManager.isDeviceInDemoMode(getContext())) { - startDemoMode(); - } - break; - } - } - - @Override - public void onSwitchUser(int userId) { - if (!mDeviceInDemoMode) { - return; - } - if (DEBUG) { - Slog.d(TAG, "onSwitchUser: " + userId); - } - final UserInfo ui = mInjector.getUserManager().getUserInfo(userId); - if (!ui.isDemo()) { - Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode"); - return; - } - if (!mIsCarrierDemoMode && !mInjector.isWakeLockHeld()) { - mInjector.acquireWakeLock(); - } - mCurrentUserId = userId; - mInjector.getActivityManagerInternal().updatePersistentConfigurationForUser( - mInjector.getSystemUsersConfiguration(), userId); - - mInjector.turnOffAllFlashLights(mCameraIdsWithFlash); - muteVolumeStreams(); - if (!mInjector.getWifiManager().isWifiEnabled()) { - mInjector.getWifiManager().setWifiEnabled(true); - } - - // Disable lock screen for demo users. - mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId); - - if (!mIsCarrierDemoMode) { - // Show reset notification (except in carrier demo mode). - mInjector.getNotificationManager().notifyAsUser(TAG, SystemMessage.NOTE_RETAIL_RESET, - mInjector.createResetNotification(), UserHandle.of(userId)); - - synchronized (mActivityLock) { - mUserUntouched = true; - } - mInjector.logSessionCount(1); - mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT); - mHandler.post(new Runnable() { - @Override - public void run() { - mPreloadAppsInstaller.installApps(userId); - } - }); - } - } - - private RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() { - private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000; - - @Override - public void onUserActivity() { - if (!mDeviceInDemoMode || mIsCarrierDemoMode) { - return; - } - long timeOfActivity = SystemClock.uptimeMillis(); - synchronized (mActivityLock) { - if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) { - return; - } - mLastUserActivityTime = timeOfActivity; - if (mUserUntouched && isDemoLauncherDisabled()) { - Slog.d(TAG, "retail_demo first touch"); - mUserUntouched = false; - mFirstUserActivityTime = timeOfActivity; - } - } - mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT); - mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, mUserInactivityTimeout); - } - }; - - static class Injector { - private Context mContext; - private UserManager mUm; - private PackageManager mPm; - private NotificationManager mNm; - private ActivityManagerService mAms; - private ActivityManagerInternal mAmi; - private AudioManager mAudioManager; - private PowerManager mPowerManager; - private CameraManager mCameraManager; - private PowerManager.WakeLock mWakeLock; - private WifiManager mWifiManager; - private Configuration mSystemUserConfiguration; - private PendingIntent mResetDemoPendingIntent; - private PreloadAppsInstaller mPreloadAppsInstaller; - - Injector(Context context) { - mContext = context; - } - - Context getContext() { - return mContext; - } - - WifiManager getWifiManager() { - if (mWifiManager == null) { - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - } - return mWifiManager; - } - - UserManager getUserManager() { - if (mUm == null) { - mUm = getContext().getSystemService(UserManager.class); - } - return mUm; - } - - void switchUser(int userId) { - if (mAms == null) { - mAms = (ActivityManagerService) ActivityManager.getService(); - } - mAms.switchUser(userId); - } - - AudioManager getAudioManager() { - if (mAudioManager == null) { - mAudioManager = getContext().getSystemService(AudioManager.class); - } - return mAudioManager; - } - - private PowerManager getPowerManager() { - if (mPowerManager == null) { - mPowerManager = (PowerManager) getContext().getSystemService( - Context.POWER_SERVICE); - } - return mPowerManager; - } - - NotificationManager getNotificationManager() { - if (mNm == null) { - mNm = NotificationManager.from(getContext()); - } - return mNm; - } - - ActivityManagerInternal getActivityManagerInternal() { - if (mAmi == null) { - mAmi = LocalServices.getService(ActivityManagerInternal.class); - } - return mAmi; - } - - CameraManager getCameraManager() { - if (mCameraManager == null) { - mCameraManager = (CameraManager) getContext().getSystemService( - Context.CAMERA_SERVICE); - } - return mCameraManager; - } - - PackageManager getPackageManager() { - if (mPm == null) { - mPm = getContext().getPackageManager(); - } - return mPm; - } - - IPackageManager getIPackageManager() { - return AppGlobals.getPackageManager(); - } - - ContentResolver getContentResolver() { - return getContext().getContentResolver(); - } - - PreloadAppsInstaller getPreloadAppsInstaller() { - if (mPreloadAppsInstaller == null) { - mPreloadAppsInstaller = new PreloadAppsInstaller(getContext()); - } - return mPreloadAppsInstaller; - } - - void systemPropertiesSet(String key, String value) { - SystemProperties.set(key, value); - } - - void turnOffAllFlashLights(String[] cameraIdsWithFlash) { - for (String cameraId : cameraIdsWithFlash) { - try { - getCameraManager().setTorchMode(cameraId, false); - } catch (CameraAccessException e) { - Slog.e(TAG, "Unable to access camera " + cameraId - + " while turning off flash", e); - } - } - } - - void initializeWakeLock() { - if (mWakeLock == null) { - mWakeLock = getPowerManager().newWakeLock( - PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG); - } - } - - void destroyWakeLock() { - mWakeLock = null; - } - - boolean isWakeLockHeld() { - return mWakeLock != null && mWakeLock.isHeld(); - } - - void acquireWakeLock() { - mWakeLock.acquire(); - } - - void releaseWakeLock() { - mWakeLock.release(); - } - - void logSessionDuration(int duration) { - MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, duration); - } - - void logSessionCount(int count) { - MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, count); - } - - Configuration getSystemUsersConfiguration() { - if (mSystemUserConfiguration == null) { - Settings.System.getConfiguration(getContentResolver(), - mSystemUserConfiguration = new Configuration()); - } - return mSystemUserConfiguration; - } - - LockPatternUtils getLockPatternUtils() { - return new LockPatternUtils(getContext()); - } - - Notification createResetNotification() { - return new Notification.Builder(getContext(), SystemNotificationChannels.RETAIL_MODE) - .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title)) - .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text)) - .setOngoing(true) - .setSmallIcon(R.drawable.platlogo) - .setShowWhen(false) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .setContentIntent(getResetDemoPendingIntent()) - .setColor(getContext().getColor(R.color.system_notification_accent_color)) - .build(); - } - - private PendingIntent getResetDemoPendingIntent() { - if (mResetDemoPendingIntent == null) { - Intent intent = new Intent(ACTION_RESET_DEMO); - mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0); - } - return mResetDemoPendingIntent; - } - - File getDataPreloadsDirectory() { - return Environment.getDataPreloadsDirectory(); - } - - File getDataPreloadsFileCacheDirectory() { - return Environment.getDataPreloadsFileCacheDirectory(); - } - - void publishLocalService(RetailDemoModeService service, - RetailDemoModeServiceInternal localService) { - service.publishLocalService(RetailDemoModeServiceInternal.class, localService); - } - } -} diff --git a/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java b/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java deleted file mode 100644 index 013eab8679a8..000000000000 --- a/services/retaildemo/java/com/android/server/retaildemo/UserInactivityCountdownDialog.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.retaildemo; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.os.CountDownTimer; -import android.view.WindowManager; -import android.widget.TextView; - -import com.android.internal.R; - -public class UserInactivityCountdownDialog extends AlertDialog { - - private OnCountDownExpiredListener mOnCountDownExpiredListener; - private CountDownTimer mCountDownTimer; - private long mCountDownDuration; - private long mRefreshInterval; - - UserInactivityCountdownDialog(Context context, long duration, long refreshInterval) { - super(context); - mCountDownDuration = duration; - mRefreshInterval = refreshInterval; - - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); - WindowManager.LayoutParams attrs = getWindow().getAttributes(); - attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; - getWindow().setAttributes(attrs); - - setTitle(R.string.demo_user_inactivity_timeout_title); - setMessage(getContext().getString(R.string.demo_user_inactivity_timeout_countdown, - duration)); - } - - public void setOnCountDownExpiredListener( - OnCountDownExpiredListener onCountDownExpiredListener) { - mOnCountDownExpiredListener = onCountDownExpiredListener; - } - - public void setPositiveButtonClickListener(OnClickListener onClickListener) { - setButton(Dialog.BUTTON_POSITIVE, - getContext().getString(R.string.demo_user_inactivity_timeout_right_button), - onClickListener); - } - - public void setNegativeButtonClickListener(OnClickListener onClickListener) { - setButton(Dialog.BUTTON_NEGATIVE, - getContext().getString(R.string.demo_user_inactivity_timeout_left_button), - onClickListener); - } - - @Override - public void show() { - super.show(); - final TextView messageView = findViewById(R.id.message); - messageView.post(new Runnable() { - @Override - public void run() { - mCountDownTimer = new CountDownTimer(mCountDownDuration, mRefreshInterval) { - - @Override - public void onTick(long millisUntilFinished) { - String msg = getContext().getString( - R.string.demo_user_inactivity_timeout_countdown, - millisUntilFinished / 1000); - messageView.setText(msg); - } - - @Override - public void onFinish() { - dismiss(); - if (mOnCountDownExpiredListener != null) - mOnCountDownExpiredListener.onCountDownExpired(); - } - }.start(); - } - }); - } - - @Override - public void onStop() { - if (mCountDownTimer != null) { - mCountDownTimer.cancel(); - } - } - - interface OnCountDownExpiredListener { - void onCountDownExpired(); - } -} diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk index 0ffe6e4db6b8..597a5849a1a0 100644 --- a/services/tests/notification/Android.mk +++ b/services/tests/notification/Android.mk @@ -18,7 +18,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ services.core \ services.devicepolicy \ services.net \ - services.retaildemo \ services.usage \ guava \ android-support-test \ diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 0ff11c1f58f8..507b4830e455 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -19,7 +19,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ services.core \ services.devicepolicy \ services.net \ - services.retaildemo \ services.usage \ guava \ android-support-test \ diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 11e383c25ef0..8decb968c8fb 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -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 @@ -894,38 +896,6 @@ public class NetworkPolicyManagerServiceTest { } @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( sTemplateWifi, 14, "US/Pacific", 1024L, 1024L, false); @@ -946,17 +916,6 @@ public class NetworkPolicyManagerServiceTest { } @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; NetworkStats stats = null; @@ -1145,15 +1104,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; callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq); @@ -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; } diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java deleted file mode 100644 index cf27a503efd4..000000000000 --- a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.retaildemo; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.IPackageInstallObserver2; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.FileUtils; -import android.os.UserHandle; -import android.provider.Settings; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.test.mock.MockContentResolver; - -import com.android.internal.util.test.FakeSettingsProvider; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.io.File; -import java.util.ArrayList; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class PreloadAppsInstallerTest { - private static final int TEST_DEMO_USER = 111; - - private Context mContext; - private @Mock IPackageManager mIpm; - private MockContentResolver mContentResolver; - private File mPreloadsAppsDirectory; - private String[] mPreloadedApps = - new String[] {"test1.apk.preload", "test2.apk.preload", "test3.apk.preload"}; - private ArrayList<String> mPreloadedAppPaths = new ArrayList<>(); - - private PreloadAppsInstaller mInstaller; - - @BeforeClass - @AfterClass - public static void clearSettingsProvider() { - FakeSettingsProvider.clearSettingsProvider(); - } - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); - mContentResolver = new MockContentResolver(mContext); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - when(mContext.getContentResolver()).thenReturn(mContentResolver); - initializePreloadedApps(); - Settings.Secure.putStringForUser(mContentResolver, - Settings.Secure.DEMO_USER_SETUP_COMPLETE, "0", TEST_DEMO_USER); - - mInstaller = new PreloadAppsInstaller(mContext, mIpm, mPreloadsAppsDirectory); - } - - private void initializePreloadedApps() throws Exception { - mPreloadsAppsDirectory = new File(InstrumentationRegistry.getContext().getFilesDir(), - "test_preload_apps_dir"); - mPreloadsAppsDirectory.mkdir(); - for (String name : mPreloadedApps) { - final File f = new File(mPreloadsAppsDirectory, name); - f.createNewFile(); - mPreloadedAppPaths.add(f.getPath()); - } - } - - @After - public void tearDown() { - if (mPreloadsAppsDirectory != null) { - FileUtils.deleteContentsAndDir(mPreloadsAppsDirectory); - } - } - - @Test - public void testInstallApps() throws Exception { - mInstaller.installApps(TEST_DEMO_USER); - for (String path : mPreloadedAppPaths) { - ArgumentCaptor<IPackageInstallObserver2> observer = - ArgumentCaptor.forClass(IPackageInstallObserver2.class); - verify(mIpm).installPackageAsUser(eq(path), observer.capture(), anyInt(), - anyString(), eq(TEST_DEMO_USER)); - observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED, - null, null); - // Verify that we try to install the package in system user. - verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM, - 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN); - } - assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed", - "1", - Settings.Secure.getStringForUser(mContentResolver, - Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER)); - } - - @Test - public void testInstallApps_noPreloads() throws Exception { - // Delete all files in preloaded apps directory - no preloaded apps - FileUtils.deleteContents(mPreloadsAppsDirectory); - mInstaller.installApps(TEST_DEMO_USER); - assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed", - "1", - Settings.Secure.getStringForUser(mContentResolver, - Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER)); - } - - @Test - public void testInstallApps_installationFails() throws Exception { - mInstaller.installApps(TEST_DEMO_USER); - for (int i = 0; i < mPreloadedAppPaths.size(); ++i) { - ArgumentCaptor<IPackageInstallObserver2> observer = - ArgumentCaptor.forClass(IPackageInstallObserver2.class); - final String path = mPreloadedAppPaths.get(i); - verify(mIpm).installPackageAsUser(eq(path), observer.capture(), anyInt(), - anyString(), eq(TEST_DEMO_USER)); - if (i == 0) { - observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_FAILED_DEXOPT, - null, null); - continue; - } - observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED, - null, null); - // Verify that we try to install the package in system user. - verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM, - 0 /*installFlags*/, PackageManager.INSTALL_REASON_UNKNOWN); - } - assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed", - "1", - Settings.Secure.getStringForUser(mContentResolver, - Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER)); - } -} diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java deleted file mode 100644 index a93f64396d57..000000000000 --- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.retaildemo; - -import static com.android.server.retaildemo.RetailDemoModeService.SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.Manifest; -import android.app.ActivityManagerInternal; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.RetailDemoModeServiceInternal; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.UserInfo; -import android.content.res.Configuration; -import android.media.AudioManager; -import android.net.Uri; -import android.net.wifi.WifiManager; -import android.os.FileUtils; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; -import android.os.UserManager; -import android.provider.CallLog; -import android.provider.MediaStore; -import android.provider.Settings; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; -import android.util.ArrayMap; - -import com.android.internal.util.test.FakeSettingsProvider; -import com.android.internal.widget.LockPatternUtils; -import com.android.server.SystemService; -import com.android.server.retaildemo.RetailDemoModeService.Injector; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.mockito.compat.ArgumentMatcher; - -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class RetailDemoModeServiceTest { - private static final int TEST_DEMO_USER = 111; - private static final long SETUP_COMPLETE_TIMEOUT_MS = 2000; // 2 sec - private static final String TEST_CAMERA_PKG = "test.cameraapp"; - private static final String TEST_PRELOADS_DIR_NAME = "test_preloads"; - - private Context mContext; - private @Mock UserManager mUm; - private @Mock PackageManager mPm; - private @Mock IPackageManager mIpm; - private @Mock NotificationManager mNm; - private @Mock ActivityManagerInternal mAmi; - private @Mock AudioManager mAudioManager; - private @Mock WifiManager mWifiManager; - private @Mock LockPatternUtils mLockPatternUtils; - private @Mock JobScheduler mJobScheduler; - private MockPreloadAppsInstaller mPreloadAppsInstaller; - private MockContentResolver mContentResolver; - private MockContactsProvider mContactsProvider; - private Configuration mConfiguration; - private File mTestPreloadsDir; - private CountDownLatch mLatch; - - private RetailDemoModeService mService; - private TestInjector mInjector; - - @BeforeClass - @AfterClass - public static void clearSettingsProvider() { - FakeSettingsProvider.clearSettingsProvider(); - } - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); - when(mContext.getSystemServiceName(eq(JobScheduler.class))).thenReturn( - Context.JOB_SCHEDULER_SERVICE); - when(mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(mJobScheduler); - when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm); - mContentResolver = new MockContentResolver(mContext); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - mContactsProvider = new MockContactsProvider(mContext); - mContentResolver.addProvider(CallLog.AUTHORITY, mContactsProvider); - when(mContext.getContentResolver()).thenReturn(mContentResolver); - mPreloadAppsInstaller = new MockPreloadAppsInstaller(mContext); - mConfiguration = new Configuration(); - mTestPreloadsDir = new File(InstrumentationRegistry.getContext().getFilesDir(), - TEST_PRELOADS_DIR_NAME); - - Settings.Global.putString(mContentResolver, Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, ""); - Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 1); - Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 1); - - // Initialize RetailDemoModeService - mInjector = new TestInjector(); - mService = new RetailDemoModeService(mInjector); - mService.onStart(); - } - - @After - public void tearDown() { - if (mTestPreloadsDir != null) { - FileUtils.deleteContentsAndDir(mTestPreloadsDir); - } - } - - @Test - public void testDemoUserSetup() throws Exception { - mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); - - mLatch = new CountDownLatch(1); - final UserInfo userInfo = new UserInfo(); - userInfo.id = TEST_DEMO_USER; - when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo); - - setCameraPackage(TEST_CAMERA_PKG); - mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); - assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set", - "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED)); - - final ArgumentCaptor<IntentFilter> intentFilter = - ArgumentCaptor.forClass(IntentFilter.class); - verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture()); - assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF, - intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF)); - - // Wait for the setup to complete. - mLatch.await(SETUP_COMPLETE_TIMEOUT_MS, TimeUnit.MILLISECONDS); - ArgumentCaptor<Integer> flags = ArgumentCaptor.forClass(Integer.class); - verify(mUm).createUser(anyString(), flags.capture()); - assertTrue("FLAG_DEMO not set during user creation", - (flags.getValue() & UserInfo.FLAG_DEMO) != 0); - assertTrue("FLAG_EPHEMERAL not set during user creation", - (flags.getValue() & UserInfo.FLAG_EPHEMERAL) != 0); - // Verify if necessary restrictions are being set. - final UserHandle user = UserHandle.of(TEST_DEMO_USER); - verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user); - verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM); - // Verify if necessary settings are updated. - assertEquals("SKIP_FIRST_USE_HINTS setting is not set for demo user", - Settings.Secure.getIntForUser(mContentResolver, - Settings.Secure.SKIP_FIRST_USE_HINTS, TEST_DEMO_USER), - 1); - assertEquals("PACKAGE_VERIFIER_ENABLE settings should be set to 0 for demo user", - Settings.Global.getInt(mContentResolver, - Settings.Global.PACKAGE_VERIFIER_ENABLE), - 0); - // Verify if camera is granted location permission. - verify(mPm).grantRuntimePermission(TEST_CAMERA_PKG, - Manifest.permission.ACCESS_FINE_LOCATION, user); - // Verify call logs are cleared. - assertTrue("Call logs should be deleted", mContactsProvider.isCallLogDeleted()); - } - - @Test - public void testSettingsObserver_disableDemoMode() throws Exception { - final RetailDemoModeService.SettingsObserver observer = - mService.new SettingsObserver(new Handler(Looper.getMainLooper())); - final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE); - when(mUm.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM)) - .thenReturn(false); - Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1); - // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially. - observer.onChange(false, deviceDemoModeUri); - final ArgumentCaptor<BroadcastReceiver> receiver = - ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class)); - - Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0); - new File(mTestPreloadsDir, "dir1").mkdirs(); - new File(mTestPreloadsDir, "file1").createNewFile(); - Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0); - observer.onChange(false, deviceDemoModeUri); - verify(mContext).unregisterReceiver(receiver.getValue()); - verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, false, UserHandle.SYSTEM); - assertEquals("Package verifier enable value has not been reset", 1, - Settings.Global.getInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE)); - Thread.sleep(20); // Wait for the deletion to complete. - // verify that the preloaded directory is emptied. - assertEquals("Preloads directory is not emptied", - 0, mTestPreloadsDir.list().length); - // Verify that the expiration job was scheduled - verify(mJobScheduler).schedule(any(JobInfo.class)); - } - - @Test - public void testSettingsObserver_enableDemoMode() throws Exception { - final RetailDemoModeService.SettingsObserver observer = - mService.new SettingsObserver(new Handler(Looper.getMainLooper())); - final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE); - // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially. - observer.onChange(false, deviceDemoModeUri); - assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set", - "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED)); - - final ArgumentCaptor<IntentFilter> intentFilter = - ArgumentCaptor.forClass(IntentFilter.class); - verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture()); - assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF, - intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF)); - } - - @Test - public void testSwitchToDemoUser() { - // To make the RetailDemoModeService update it's internal state. - mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); - final RetailDemoModeService.SettingsObserver observer = - mService.new SettingsObserver(new Handler(Looper.getMainLooper())); - observer.onChange(false, Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE)); - - final UserInfo userInfo = new UserInfo(TEST_DEMO_USER, "demo_user", - UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL); - when(mUm.getUserInfo(TEST_DEMO_USER)).thenReturn(userInfo); - when(mWifiManager.isWifiEnabled()).thenReturn(false); - final int minVolume = -111; - for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) { - when(mAudioManager.getStreamMinVolume(stream)).thenReturn(minVolume); - } - - mService.onSwitchUser(TEST_DEMO_USER); - verify(mAmi).updatePersistentConfigurationForUser(mConfiguration, TEST_DEMO_USER); - for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) { - verify(mAudioManager).setStreamVolume(stream, minVolume, 0); - } - verify(mLockPatternUtils).setLockScreenDisabled(true, TEST_DEMO_USER); - verify(mWifiManager).setWifiEnabled(true); - } - - private void setCameraPackage(String pkgName) { - final ResolveInfo ri = new ResolveInfo(); - final ActivityInfo ai = new ActivityInfo(); - ai.packageName = pkgName; - ri.activityInfo = ai; - when(mPm.resolveActivityAsUser( - argThat(new IntentMatcher(MediaStore.ACTION_IMAGE_CAPTURE)), - anyInt(), - eq(TEST_DEMO_USER))).thenReturn(ri); - } - - private class IntentMatcher extends ArgumentMatcher<Intent> { - private final Intent mIntent; - - IntentMatcher(String action) { - mIntent = new Intent(action); - } - - @Override - public boolean matchesObject(Object argument) { - if (argument instanceof Intent) { - return ((Intent) argument).filterEquals(mIntent); - } - return false; - } - - @Override - public String toString() { - return "Expected: " + mIntent; - } - } - - private class MockContactsProvider extends MockContentProvider { - private boolean mCallLogDeleted; - - MockContactsProvider(Context context) { - super(context); - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - if (CallLog.Calls.CONTENT_URI.equals(uri)) { - mCallLogDeleted = true; - } - return 0; - } - - public boolean isCallLogDeleted() { - return mCallLogDeleted; - } - } - - private class MockPreloadAppsInstaller extends PreloadAppsInstaller { - MockPreloadAppsInstaller(Context context) { - super(context); - } - - @Override - public void installApps(int userId) { - } - } - - private class TestInjector extends Injector { - private ArrayMap<String, String> mSystemProperties = new ArrayMap<>(); - - TestInjector() { - super(mContext); - } - - @Override - Context getContext() { - return mContext; - } - - @Override - UserManager getUserManager() { - return mUm; - } - - @Override - WifiManager getWifiManager() { - return mWifiManager; - } - - @Override - void switchUser(int userId) { - if (mLatch != null) { - mLatch.countDown(); - } - } - - @Override - AudioManager getAudioManager() { - return mAudioManager; - } - - @Override - NotificationManager getNotificationManager() { - return mNm; - } - - @Override - ActivityManagerInternal getActivityManagerInternal() { - return mAmi; - } - - @Override - PackageManager getPackageManager() { - return mPm; - } - - @Override - IPackageManager getIPackageManager() { - return mIpm; - } - - @Override - ContentResolver getContentResolver() { - return mContentResolver; - } - - @Override - PreloadAppsInstaller getPreloadAppsInstaller() { - return mPreloadAppsInstaller; - } - - @Override - void systemPropertiesSet(String key, String value) { - mSystemProperties.put(key, value); - } - - @Override - void turnOffAllFlashLights(String[] cameraIdsWithFlash) { - } - - @Override - void initializeWakeLock() { - } - - @Override - void destroyWakeLock() { - } - - @Override - boolean isWakeLockHeld() { - return false; - } - - @Override - void acquireWakeLock() { - } - - @Override - void releaseWakeLock() { - } - - @Override - void logSessionDuration(int duration) { - } - - @Override - void logSessionCount(int count) { - } - - @Override - Configuration getSystemUsersConfiguration() { - return mConfiguration; - } - - @Override - LockPatternUtils getLockPatternUtils() { - return mLockPatternUtils; - } - - @Override - Notification createResetNotification() { - return null; - } - - @Override - File getDataPreloadsDirectory() { - return mTestPreloadsDir; - } - - @Override - File getDataPreloadsFileCacheDirectory() { - return new File(mTestPreloadsDir, "file_cache"); - } - - @Override - void publishLocalService(RetailDemoModeService service, - RetailDemoModeServiceInternal localService) { - } - - String systemPropertiesGet(String key) { - return mSystemProperties.get(key); - } - } -} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 8b3a804d35f9..0001d42f4329 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -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; @@ -262,6 +263,17 @@ public class CarrierConfigManager { "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. * diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 89c9134f2be2..503bf820c9a0 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -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(); - } - } } diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java index da7661aeb787..c9419c535b82 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/telephony/java/android/telephony/SubscriptionPlan.java @@ -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 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. + * 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() { - 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; - } + return cycleRule.cycleIterator(); } + /** + * Builder for a {@link SubscriptionPlan}. + */ 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 (dataUsageTime < TIME_UNKNOWN) { - throw new IllegalArgumentException("Time must be positive or TIME_UNKNOWN"); + if (dataUsageBytes < 0) { + throw new IllegalArgumentException("Usage bytes must be positive"); } - 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; diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl index d77b27f8295a..511573170bb0 100644 --- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl +++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl @@ -28,4 +28,7 @@ interface ICarrierConfigLoader { void notifyConfigChangedForSubId(int subId); void updateConfigForPhoneId(int phoneId, String simState); + + String getDefaultCarrierServicePackageName(); + } |