diff options
93 files changed, 2167 insertions, 2845 deletions
diff --git a/Android.mk b/Android.mk index 37301729ea75..4695a1970cbc 100644 --- a/Android.mk +++ b/Android.mk @@ -247,6 +247,7 @@ LOCAL_SRC_FILES += \ core/java/android/nfc/INfcCardEmulation.aidl \ core/java/android/nfc/INfcFCardEmulation.aidl \ core/java/android/nfc/INfcUnlockHandler.aidl \ + core/java/android/nfc/INfcDta.aidl \ core/java/android/nfc/ITagRemovedCallback.aidl \ core/java/android/os/IBatteryPropertiesListener.aidl \ core/java/android/os/IBatteryPropertiesRegistrar.aidl \ diff --git a/api/current.txt b/api/current.txt index e14979785492..2428da1a4390 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27070,7 +27070,8 @@ package android.net.wifi.p2p { method public abstract void onSuccess(); } - public static class WifiP2pManager.Channel { + public static class WifiP2pManager.Channel implements java.lang.AutoCloseable { + method public void close(); } public static abstract interface WifiP2pManager.ChannelListener { @@ -37767,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(); @@ -39535,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"; @@ -39577,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"; @@ -39636,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"; @@ -40148,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 @@ -40163,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); @@ -52263,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 f7a576e645f5..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"; @@ -29866,7 +29865,8 @@ package android.net.wifi.p2p { method public abstract void onSuccess(); } - public static class WifiP2pManager.Channel { + public static class WifiP2pManager.Channel implements java.lang.AutoCloseable { + method public void close(); } public static abstract interface WifiP2pManager.ChannelListener { @@ -41096,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(); @@ -43082,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"; @@ -43124,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"; @@ -43183,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"; @@ -43697,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 @@ -43712,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); @@ -56293,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 bd93e1b6407d..62f8418b4a71 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -27181,7 +27181,8 @@ package android.net.wifi.p2p { method public abstract void onSuccess(); } - public static class WifiP2pManager.Channel { + public static class WifiP2pManager.Channel implements java.lang.AutoCloseable { + method public void close(); } public static abstract interface WifiP2pManager.ChannelListener { @@ -37977,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(); @@ -39761,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"; @@ -39803,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"; @@ -39862,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"; @@ -40374,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 @@ -40389,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); @@ -52700,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/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0f0c4bac5f9f..885817231175 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -416,12 +416,16 @@ public class NotificationManager { * Creates a notification channel that notifications can be posted to. * * This can also be used to restore a deleted channel and to update an existing channel's - * name and description. + * name, description, and/or importance. * * <p>The name and description should only be changed if the locale changes * or in response to the user renaming this channel. For example, if a user has a channel * named 'John Doe' that represents messages from a 'John Doe', and 'John Doe' changes his name * to 'John Smith,' the channel can be renamed to match. + * + * <p>The importance of an existing channel will only be changed if the new importance is lower + * than the current value and the user has not altered any settings on this channel. + * * All other fields are ignored for channels that already exist. * * @param channel the channel to create. Note that the created channel may differ from this 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/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index f991efed07eb..6801618e6a68 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -29,6 +29,7 @@ import android.nfc.INfcCardEmulation; import android.nfc.INfcFCardEmulation; import android.nfc.INfcUnlockHandler; import android.nfc.ITagRemovedCallback; +import android.nfc.INfcDta; import android.os.Bundle; /** @@ -40,7 +41,7 @@ interface INfcAdapter INfcCardEmulation getNfcCardEmulationInterface(); INfcFCardEmulation getNfcFCardEmulationInterface(); INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg); - + INfcDta getNfcDtaInterface(in String pkg); int getState(); boolean disable(boolean saveState); boolean enable(); diff --git a/core/java/android/nfc/INfcDta.aidl b/core/java/android/nfc/INfcDta.aidl new file mode 100644 index 000000000000..4cc59271362b --- /dev/null +++ b/core/java/android/nfc/INfcDta.aidl @@ -0,0 +1,34 @@ + /* + * Copyright (C) 2017 NXP Semiconductors + * + * 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.nfc; + +import android.os.Bundle; + +/** + * {@hide} + */ +interface INfcDta { + + void enableDta(); + void disableDta(); + boolean enableServer(String serviceName, int serviceSap, int miu, + int rwSize,int testCaseId); + void disableServer(); + boolean enableClient(String serviceName, int miu, int rwSize, + int testCaseId); + void disableClient(); + boolean registerMessageService(String msgServiceName); +} diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 48869c71b685..debef6310f14 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -16,8 +16,6 @@ package android.nfc; -import java.util.HashMap; - import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -43,6 +41,7 @@ import android.os.ServiceManager; import android.util.Log; import java.io.IOException; +import java.util.HashMap; /** * Represents the local NFC adapter. @@ -627,6 +626,23 @@ public final class NfcAdapter { } /** + * Returns the binder interface to the NFC-DTA test interface. + * @hide + */ + public INfcDta getNfcDtaInterface() { + if (mContext == null) { + throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " + + " NFC extras APIs"); + } + try { + return sService.getNfcDtaInterface(mContext.getPackageName()); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return null; + } + } + + /** * NFC service dead - attempt best effort recovery * @hide */ diff --git a/core/java/android/nfc/dta/NfcDta.java b/core/java/android/nfc/dta/NfcDta.java new file mode 100644 index 000000000000..88016623434d --- /dev/null +++ b/core/java/android/nfc/dta/NfcDta.java @@ -0,0 +1,167 @@ +/* + * 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.nfc.dta; + +import android.content.Context; +import android.nfc.INfcDta; +import android.nfc.NfcAdapter; +import android.os.RemoteException; +import android.util.Log; + +import java.util.HashMap; + +/** + * This class provides the primary API for DTA operations. + * @hide + */ +public final class NfcDta { + private static final String TAG = "NfcDta"; + + private static INfcDta sService; + private static HashMap<Context, NfcDta> sNfcDtas = new HashMap<Context, NfcDta>(); + + private final Context mContext; + + private NfcDta(Context context, INfcDta service) { + mContext = context.getApplicationContext(); + sService = service; + } + + /** + * Helper to get an instance of this class. + * + * @param adapter A reference to an NfcAdapter object. + * @return + */ + public static synchronized NfcDta getInstance(NfcAdapter adapter) { + if (adapter == null) throw new NullPointerException("NfcAdapter is null"); + Context context = adapter.getContext(); + if (context == null) { + Log.e(TAG, "NfcAdapter context is null."); + throw new UnsupportedOperationException(); + } + + NfcDta manager = sNfcDtas.get(context); + if (manager == null) { + INfcDta service = adapter.getNfcDtaInterface(); + if (service == null) { + Log.e(TAG, "This device does not implement the INfcDta interface."); + throw new UnsupportedOperationException(); + } + manager = new NfcDta(context, service); + sNfcDtas.put(context, manager); + } + return manager; + } + + /** + * Enables DTA mode + * + * @return true/false if enabling was successful + */ + public boolean enableDta() { + try { + sService.enableDta(); + } catch (RemoteException e) { + return false; + } + return true; + } + + /** + * Disables DTA mode + * + * @return true/false if disabling was successful + */ + public boolean disableDta() { + try { + sService.disableDta(); + } catch (RemoteException e) { + return false; + } + return true; + } + + /** + * Enables Server + * + * @return true/false if enabling was successful + */ + public boolean enableServer(String serviceName, int serviceSap, int miu, + int rwSize, int testCaseId) { + try { + return sService.enableServer(serviceName, serviceSap, miu, rwSize, testCaseId); + } catch (RemoteException e) { + return false; + } + } + + /** + * Disables Server + * + * @return true/false if disabling was successful + */ + public boolean disableServer() { + try { + sService.disableServer(); + } catch (RemoteException e) { + return false; + } + return true; + } + + /** + * Enables Client + * + * @return true/false if enabling was successful + */ + public boolean enableClient(String serviceName, int miu, int rwSize, + int testCaseId) { + try { + return sService.enableClient(serviceName, miu, rwSize, testCaseId); + } catch (RemoteException e) { + return false; + } + } + + /** + * Disables client + * + * @return true/false if disabling was successful + */ + public boolean disableClient() { + try { + sService.disableClient(); + } catch (RemoteException e) { + return false; + } + return true; + } + + /** + * Registers Message Service + * + * @return true/false if registration was successful + */ + public boolean registerMessageService(String msgServiceName) { + try { + return sService.registerMessageService(msgServiceName); + } catch (RemoteException e) { + return false; + } + } +} 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/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index b22501823020..6ba11b9954c4 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -85,7 +85,7 @@ public class ZenModeConfig implements Parcelable { private static final boolean DEFAULT_ALLOW_SCREEN_ON = true; private static final int XML_VERSION = 2; - private static final String ZEN_TAG = "zen"; + public static final String ZEN_TAG = "zen"; private static final String ZEN_ATT_VERSION = "version"; private static final String ZEN_ATT_USER = "user"; private static final String ALLOW_TAG = "allow"; 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/AtomicFile.java b/core/java/android/util/AtomicFile.java index 2f1abe9a4c8d..0122e49eb462 100644 --- a/core/java/android/util/AtomicFile.java +++ b/core/java/android/util/AtomicFile.java @@ -202,6 +202,15 @@ public class AtomicFile { } /** + * @hide + * Checks if the original or backup file exists. + * @return whether the original or backup file exists. + */ + public boolean exists() { + return mBaseName.exists() || mBackupName.exists(); + } + + /** * Gets the last modified time of the atomic file. * {@hide} * 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/Display.java b/core/java/android/view/Display.java index 7346a215ed8e..263d3ff423c5 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1133,6 +1133,15 @@ public final class Display { } /** + * Returns true if the display may be in a reduced operating mode while in the + * specified display power state. + * @hide + */ + public static boolean isDozeState(int state) { + return state == STATE_DOZE || state == STATE_DOZE_SUSPEND; + } + + /** * A mode supported by a given display. * * @see Display#getSupportedModes() 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/config.xml b/core/res/res/values/config.xml index 2fede7cc4844..4b76378068cc 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1897,6 +1897,11 @@ states. --> <bool name="config_dozeAlwaysOnDisplayAvailable">false</bool> + <!-- Whether the display hardware requires we go to the off state before transitioning + out of any doze states. --> + <bool name="config_displayTransitionOffAfterDoze">false</bool> + + <!-- Power Management: Specifies whether to decouple the auto-suspend state of the device from the display on/off state. 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/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bab0c852153a..4b24c4a7b635 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3051,6 +3051,7 @@ <java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" /> <java-symbol type="integer" name="config_inCallNotificationVolumeRelative" /> <java-symbol type="bool" name="config_dozeAlwaysOnDisplayAvailable" /> + <java-symbol type="bool" name="config_displayTransitionOffAfterDoze" /> <java-symbol type="integer" name="config_storageManagerDaystoRetainDefault" /> <java-symbol type="string" name="config_headlineFontFamily" /> <java-symbol type="string" name="config_headlineFontFamilyLight" /> 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/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 01d901496125..0f8d2f9e3ca7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1099,7 +1099,7 @@ public class AccessPoint implements Comparable<AccessPoint> { // are still seen, we will investigate further. update(config); // Notifies the AccessPointListener of the change } - if (mRssi != info.getRssi()) { + if (mRssi != info.getRssi() && info.getRssi() != WifiInfo.INVALID_RSSI) { mRssi = info.getRssi(); updated = true; } else if (mNetworkInfo != null && networkInfo != null diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 9a3f21f8654e..c081b350e823 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -648,6 +648,57 @@ public class AccessPointTest { } @Test + public void testUpdateWithDifferentRssi_returnsTrue() { + int networkId = 123; + int rssi = -55; + WifiConfiguration config = new WifiConfiguration(); + config.networkId = networkId; + WifiInfo wifiInfo = new WifiInfo(); + wifiInfo.setNetworkId(networkId); + wifiInfo.setRssi(rssi); + + NetworkInfo networkInfo = + new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); + networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", ""); + + AccessPoint ap = new TestAccessPointBuilder(mContext) + .setNetworkInfo(networkInfo) + .setNetworkId(networkId) + .setRssi(rssi) + .setWifiInfo(wifiInfo) + .build(); + + NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values + wifiInfo.setRssi(rssi + 1); + assertThat(ap.update(config, wifiInfo, newInfo)).isTrue(); + } + + @Test + public void testUpdateWithInvalidRssi_returnsFalse() { + int networkId = 123; + int rssi = -55; + WifiConfiguration config = new WifiConfiguration(); + config.networkId = networkId; + WifiInfo wifiInfo = new WifiInfo(); + wifiInfo.setNetworkId(networkId); + wifiInfo.setRssi(rssi); + + NetworkInfo networkInfo = + new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", ""); + networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", ""); + + AccessPoint ap = new TestAccessPointBuilder(mContext) + .setNetworkInfo(networkInfo) + .setNetworkId(networkId) + .setRssi(rssi) + .setWifiInfo(wifiInfo) + .build(); + + NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values + wifiInfo.setRssi(WifiInfo.INVALID_RSSI); + assertThat(ap.update(config, wifiInfo, newInfo)).isFalse(); + } + @Test public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() { int networkId = 123; int rssi = -55; 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/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 15e6e4594699..146b34947678 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -2594,7 +2594,7 @@ public class SettingsProvider extends ContentProvider { synchronized (mLock) { final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); File globalFile = getSettingsFile(key); - if (globalFile.exists()) { + if (SettingsState.stateFileExists(globalFile)) { return; } @@ -2631,7 +2631,7 @@ public class SettingsProvider extends ContentProvider { // Every user has secure settings and if no file we need to migrate. final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId); File secureFile = getSettingsFile(secureKey); - if (secureFile.exists()) { + if (SettingsState.stateFileExists(secureFile)) { return; } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 5f4b2391a763..d3ac11a7942e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -689,17 +689,11 @@ final class SettingsState { private void readStateSyncLocked() { FileInputStream in; - if (!mStatePersistFile.exists()) { - Slog.i(LOG_TAG, "No settings state " + mStatePersistFile); - addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); - return; - } try { in = new AtomicFile(mStatePersistFile).openRead(); } catch (FileNotFoundException fnfe) { - String message = "No settings state " + mStatePersistFile; - Slog.wtf(LOG_TAG, message); - Slog.i(LOG_TAG, message); + Slog.i(LOG_TAG, "No settings state " + mStatePersistFile); + addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); return; } try { @@ -715,6 +709,16 @@ final class SettingsState { } } + /** + * Uses AtomicFile to check if the file or its backup exists. + * @param file The file to check for existence + * @return whether the original or backup exist + */ + public static boolean stateFileExists(File file) { + AtomicFile stateFile = new AtomicFile(file); + return stateFile.exists(); + } + private void parseStateLocked(XmlPullParser parser) throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); 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/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 979361584f7b..c8e6021d6f89 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -801,6 +801,9 @@ <!-- The shortest-edge size of the expanded PiP. --> <dimen name="pip_expanded_shortest_edge_size">160dp</dimen> + <!-- The additional offset to apply to the IME animation to account for the input field. --> + <dimen name="pip_ime_offset">48dp</dimen> + <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect the configuration of the device, so we can't use -land resources. --> <dimen name="pip_between_action_padding_land">8dp</dimen> 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/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 0be4eda8a069..a1dfeb34a670 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -91,6 +91,7 @@ public class DozeMachine { case UNINITIALIZED: case INITIALIZED: case DOZE: + case DOZE_REQUEST_PULSE: case DOZE_AOD_PAUSED: return Display.STATE_OFF; case DOZE_PULSING: 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/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6d10d9413e66..e23875f6c094 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -811,6 +811,7 @@ public class KeyguardViewMediator extends SystemUI { synchronized (this) { mDeviceInteractive = false; mGoingToSleep = false; + mWakeAndUnlocking = false; resetKeyguardDonePendingLocked(); mHideAnimationRun = false; @@ -1957,7 +1958,6 @@ public class KeyguardViewMediator extends SystemUI { if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff"); mStatusBarKeyguardViewManager.onScreenTurnedOff(); mDrawnCallback = null; - mWakeAndUnlocking = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 278fdc3a6ded..d3be19d3df87 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -27,6 +27,7 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; +import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -122,6 +123,7 @@ public class PipTouchHandler { private boolean mIsMinimized; private boolean mIsImeShowing; private int mImeHeight; + private int mImeOffset; private float mSavedSnapFraction = -1f; private boolean mSendingHoverAccessibilityEvents; private boolean mMovementWithinMinimize; @@ -192,8 +194,11 @@ public class PipTouchHandler { }; mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mMenuController, mSnapAlgorithm, mFlingAnimationUtils); - mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize( + + Resources res = context.getResources(); + mExpandedShortestEdgeSize = res.getDimensionPixelSize( R.dimen.pip_expanded_shortest_edge_size); + mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset); // Register the listener for input consumer touch events inputConsumerController.setTouchListener(this::handleTouchEvent); @@ -265,7 +270,6 @@ public class PipTouchHandler { mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds, mIsImeShowing ? mImeHeight : 0); - // If this is from an IME adjustment, then we should move the PiP so that it is not occluded // by the IME if (fromImeAdjustement) { @@ -278,18 +282,22 @@ public class PipTouchHandler { ? expandedMovementBounds : normalMovementBounds; if (mIsImeShowing) { - // IME visible + // IME visible, apply the IME offset if the space allows for it + final int imeOffset = toMovementBounds.bottom - Math.max(toMovementBounds.top, + toMovementBounds.bottom - mImeOffset); if (bounds.top == mMovementBounds.bottom) { // If the PIP is currently resting on top of the IME, then adjust it with - // the hiding IME - bounds.offsetTo(bounds.left, toMovementBounds.bottom); + // the showing IME + bounds.offsetTo(bounds.left, toMovementBounds.bottom - imeOffset); } else { - bounds.offset(0, Math.min(0, toMovementBounds.bottom - bounds.top)); + bounds.offset(0, Math.min(0, toMovementBounds.bottom - imeOffset + - bounds.top)); } } else { // IME hidden - if (bounds.top == mMovementBounds.bottom) { - // If the PIP is resting on top of the IME, then adjust it with the hiding IME + if (bounds.top >= (mMovementBounds.bottom - mImeOffset)) { + // If the PIP is resting on top of the IME, then adjust it with the hiding + // IME bounds.offsetTo(bounds.left, toMovementBounds.bottom); } } 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/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index f59152497939..2dc467f2add1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -114,6 +114,7 @@ public class DozeScrimController { // be invoked when we're done so that the caller can drop the pulse wakelock. mPulseCallback = callback; mPulseReason = reason; + mScrimController.setDozeInFrontAlpha(1f); mHandler.post(mPulseIn); } @@ -290,10 +291,6 @@ public class DozeScrimController { // Signal that the pulse is ready to turn the screen on and draw. pulseStarted(); - - if (mDozeParameters.getAlwaysOn()) { - mHandler.post(DozeScrimController.this::onScreenTurnedOn); - } } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index 5af80f546f48..df059e3686ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -285,7 +285,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { if (!mUpdateMonitor.isDeviceInteractive()) { if (!mStatusBarKeyguardViewManager.isShowing()) { return MODE_ONLY_WAKE; - } else if (pulsingOrAod() && unlockingAllowed) { + } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { return MODE_WAKE_AND_UNLOCK_PULSING; } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) { return MODE_WAKE_AND_UNLOCK; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index a8b1c91fc235..62d4b736d93a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -25,7 +25,6 @@ import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.util.Log; import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; @@ -120,6 +119,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private boolean mKeyguardFadingOutInProgress; private boolean mAnimatingDozeUnlock; private ValueAnimator mKeyguardFadeoutAnimation; + /** Wake up from AOD transition is starting; need fully opaque front scrim */ + private boolean mWakingUpFromAodStarting; + /** Wake up from AOD transition is in progress; need black tint */ + private boolean mWakingUpFromAodInProgress; + /** Wake up from AOD transition is animating; need to reset when animation finishes */ + private boolean mWakingUpFromAodAnimationRunning; public ScrimController(LightBarController lightBarController, ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) { @@ -187,9 +192,32 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, scheduleUpdate(); } + public void prepareWakeUpFromAod() { + mWakingUpFromAodInProgress = true; + mWakingUpFromAodStarting = true; + mAnimateChange = false; + scheduleUpdate(); + onPreDraw(); + } + + public void wakeUpFromAod() { + if (mWakeAndUnlocking || mAnimateKeyguardFadingOut) { + // Wake and unlocking has a separate transition that must not be interfered with. + mWakingUpFromAodStarting = false; + return; + } + if (mWakingUpFromAodStarting) { + mWakingUpFromAodInProgress = true; + mWakingUpFromAodStarting = false; + mAnimateChange = true; + scheduleUpdate(); + } + } + public void setWakeAndUnlocking() { mWakeAndUnlocking = true; mAnimatingDozeUnlock = true; + mWakingUpFromAodStarting = false; scheduleUpdate(); } @@ -356,7 +384,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, setScrimBehindAlpha(mScrimBehindAlpha); } else { float fraction = Math.max(0, Math.min(mFraction, 1)); - setScrimInFrontAlpha(0f); + if (mWakingUpFromAodStarting) { + setScrimInFrontAlpha(1f); + } else { + setScrimInFrontAlpha(0f); + } setScrimBehindAlpha(fraction * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking) + mScrimBehindAlphaUnlocking); @@ -426,7 +458,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, scrimView.setViewAlpha(alpha); int dozeTint = Color.TRANSPARENT; - if (mAnimatingDozeUnlock || mDozing) { + + boolean dozing = mAnimatingDozeUnlock || mDozing; + boolean frontScrimDozing = mWakingUpFromAodInProgress; + if (dozing || frontScrimDozing && scrim == mScrimInFront) { dozeTint = Color.BLACK; } scrimView.setTint(dozeTint); @@ -458,6 +493,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mKeyguardFadingOutInProgress = false; mAnimatingDozeUnlock = false; } + if (mWakingUpFromAodAnimationRunning) { + mWakingUpFromAodAnimationRunning = false; + mWakingUpFromAodInProgress = false; + } scrim.setTag(TAG_KEY_ANIM, null); scrim.setTag(TAG_KEY_ANIM_TARGET, null); } @@ -467,6 +506,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, mKeyguardFadingOutInProgress = true; mKeyguardFadeoutAnimation = anim; } + if (mWakingUpFromAodInProgress) { + mWakingUpFromAodAnimationRunning = true; + } if (mSkipFirstFrame) { anim.setCurrentPlayTime(16); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 4518ee9cb884..353b82b6fd6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -21,6 +21,9 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.windowStateToString; import static android.content.res.Configuration.UI_MODE_TYPE_CAR; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; +import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; @@ -4219,13 +4222,16 @@ public class StatusBar extends SystemUI implements DemoMode, } private boolean updateIsKeyguard() { + boolean wakeAndUnlocking = mFingerprintUnlockController.getMode() + == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK; + // For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise // there's no surface we can show to the user. Note that the device goes fully interactive // late in the transition, so we also allow the device to start dozing once the screen has // turned off fully. boolean keyguardForDozing = mDozingRequested && (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard)); - boolean shouldBeKeyguard = mKeyguardRequested || keyguardForDozing; + boolean shouldBeKeyguard = (mKeyguardRequested || keyguardForDozing) && !wakeAndUnlocking; if (keyguardForDozing) { updatePanelExpansionForKeyguard(); } @@ -4267,7 +4273,8 @@ public class StatusBar extends SystemUI implements DemoMode, } private void updatePanelExpansionForKeyguard() { - if (mState == StatusBarState.KEYGUARD) { + if (mState == StatusBarState.KEYGUARD && mFingerprintUnlockController.getMode() + != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) { instantExpandNotificationsPanel(); } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) { instantCollapseNotificationPanel(); @@ -5167,6 +5174,13 @@ public class StatusBar extends SystemUI implements DemoMode, public void onScreenTurningOn() { mFalsingManager.onScreenTurningOn(); mNotificationPanel.onScreenTurningOn(); + + int wakefulness = mWakefulnessLifecycle.getWakefulness(); + if (mDozing && (wakefulness == WAKEFULNESS_WAKING + || wakefulness == WAKEFULNESS_ASLEEP) && !isPulsing()) { + mScrimController.prepareWakeUpFromAod(); + } + if (mLaunchCameraOnScreenTurningOn) { mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); mLaunchCameraOnScreenTurningOn = false; @@ -5175,13 +5189,18 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onScreenTurnedOn() { + mScrimController.wakeUpFromAod(); mDozeScrimController.onScreenTurnedOn(); } @Override public void onScreenTurnedOff() { mFalsingManager.onScreenOff(); - updateIsKeyguard(); + // If we pulse in from AOD, we turn the screen off first. However, updatingIsKeyguard + // in that case destroys the HeadsUpManager state, so don't do it in that case. + if (!isPulsing()) { + updateIsKeyguard(); + } } }; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java index 203876b9a2f5..e54c7924fc66 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java @@ -86,13 +86,13 @@ public class DozeScreenStateTest extends SysuiTestCase { } @Test - public void testScreen_onInRequestPulseWithAoD() { + public void testScreen_offInRequestPulseWithAoD() { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE); - assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState); + assertEquals(Display.STATE_OFF, mServiceFake.screenState); } }
\ 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/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index d4abc08ffc0d..fb911ce05254 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -169,6 +169,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // a stylish color fade animation instead. private boolean mColorFadeFadesConfig; + // True if we need to transition to the off state when coming out of a doze state. + // Some display hardware will show artifacts (flickers, etc) when transitioning from a doze + // to a fully on state. In order to hide these, we first transition to off to let the system + // animate the screen on as it normally would, which is a much smoother experience. + private boolean mTransitionOffAfterDozeConfig; + // The pending power request. // Initially null until the first call to requestPowerState. // Guarded by mLock. @@ -416,6 +422,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mColorFadeFadesConfig = resources.getBoolean( com.android.internal.R.bool.config_animateScreenLights); + mTransitionOffAfterDozeConfig = resources.getBoolean( + com.android.internal.R.bool.config_displayTransitionOffAfterDoze); + if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) { mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); if (mProximitySensor != null) { @@ -885,6 +894,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private boolean setScreenState(int state) { + return setScreenState(state, false /*force*/); + } + + private boolean setScreenState(int state, boolean force) { final boolean isOff = (state == Display.STATE_OFF); if (mPowerState.getScreenState() != state) { @@ -895,9 +908,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_OFF; blockScreenOff(); mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker); - return false; + if (force) { + // If we're forcing the power state transition then immediately + // unblock the screen off event. This keeps the lifecycle consistent, + // so WindowManagerPolicy will always see screenTurningOff before + // screenTurnedOff, but we don't actually block on them for the state + // change. + unblockScreenOff(); + } else { + return false; + } } else if (mPendingScreenOffUnblocker != null) { - // Abort doing the state change until screen off is unblocked. return false; } @@ -976,6 +997,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mPendingScreenOff = false; } + if (mTransitionOffAfterDozeConfig && + Display.isDozeState(mPowerState.getScreenState()) + && !Display.isDozeState(target)) { + setScreenState(Display.STATE_OFF, true /*force*/); + // Skip the screen off animation and add a black surface to hide the + // contents of the screen. This will also trigger another power state update so that we + // end up converging on the target state. + mColorFadeOffAnimator.end(); + return; + } + // If we were in the process of turning off the screen but didn't quite // finish. Then finish up now to prevent a jarring transition back // to screen on if we skipped blocking screen on as usual. 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/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 5cc14b5ed520..3444ef3ec2fa 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -35,6 +35,7 @@ import android.util.ArraySet; import android.util.Slog; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.notification.NotificationManagerService.DumpFilter; import java.io.PrintWriter; @@ -43,7 +44,8 @@ import java.util.Arrays; public class ConditionProviders extends ManagedServices { - private static final String TAG_ENABLED_DND_APPS = "dnd_apps"; + @VisibleForTesting + static final String TAG_ENABLED_DND_APPS = "dnd_apps"; private final ArrayList<ConditionRecord> mRecords = new ArrayList<>(); private final ArraySet<String> mSystemConditionProviderNames; @@ -84,7 +86,7 @@ public class ConditionProviders extends ManagedServices { c.caption = "condition provider"; c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE; c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES; - c.managedServiceTypeTag = TAG_ENABLED_DND_APPS; + c.xmlTag = TAG_ENABLED_DND_APPS; c.secondarySettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE; c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS; diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 2f88740cd01b..80878131ae44 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -52,6 +52,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.util.XmlUtils; import com.android.server.notification.NotificationManagerService.DumpFilter; import org.xmlpull.v1.XmlPullParser; @@ -226,7 +227,7 @@ abstract public class ManagedServices { } public void writeXml(XmlSerializer out, boolean forBackup) throws IOException { - out.startTag(null, getConfig().managedServiceTypeTag); + out.startTag(null, getConfig().xmlTag); if (forBackup) { trimApprovedListsAccordingToInstalledServices(); @@ -241,7 +242,7 @@ abstract public class ManagedServices { for (int j = 0; j < M; j++) { final boolean isPrimary = approvedByType.keyAt(j); final Set<String> approved = approvedByType.valueAt(j); - if (approved != null && approved.size() > 0) { + if (approved != null) { String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved); out.startTag(null, TAG_MANAGED_SERVICES); out.attribute(null, ATT_APPROVED_LIST, allowedItems); @@ -260,43 +261,34 @@ abstract public class ManagedServices { } } - out.endTag(null, getConfig().managedServiceTypeTag); + out.endTag(null, getConfig().xmlTag); } - /** - * @return false if modifications were made to the data on load that requires the xml file - * to be re-written - */ - public boolean readXml(XmlPullParser parser) + protected void migrateToXml() { + loadAllowedComponentsFromSettings(); + } + + public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException { - boolean rewriteXml = false; - int type = parser.getEventType(); - String tag = parser.getName(); - if (type != XmlPullParser.START_TAG || !getConfig().managedServiceTypeTag.equals(tag)) { - // xml empty/invalid - read from setting instead - loadAllowedComponentsFromSettings(); - rewriteXml = true; - } else { - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { - tag = parser.getName(); - if (type == XmlPullParser.END_TAG - && getConfig().managedServiceTypeTag.equals(tag)) { - break; - } - if (type == XmlPullParser.START_TAG) { - if (TAG_MANAGED_SERVICES.equals(tag)) { - final String approved = XmlUtils.safeString(parser, ATT_APPROVED_LIST, ""); - final int userId = XmlUtils.safeInt(parser, ATT_USER_ID, 0); - final boolean isPrimary = XmlUtils.safeBool(parser, ATT_IS_PRIMARY, true); - addApprovedList(approved, userId, isPrimary); - } + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + String tag = parser.getName(); + if (type == XmlPullParser.END_TAG + && getConfig().xmlTag.equals(tag)) { + break; + } + if (type == XmlPullParser.START_TAG) { + if (TAG_MANAGED_SERVICES.equals(tag)) { + final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST); + final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0); + final boolean isPrimary = + XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true); + addApprovedList(approved, userId, isPrimary); + mUseXml = true; } } - mUseXml = true; } rebindServices(false); - - return rewriteXml; } private void loadAllowedComponentsFromSettings() { @@ -1119,7 +1111,7 @@ abstract public class ManagedServices { public String serviceInterface; public String secureSettingName; public String secondarySettingName; - public String managedServiceTypeTag; + public String xmlTag; public String bindPermission; public String settingsAction; public int clientLabel; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a57a8e5860e3..fb391f885874 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -55,7 +55,6 @@ import static android.service.notification.NotificationListenerService.TRIM_LIGH import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import android.Manifest; import android.annotation.NonNull; @@ -162,6 +161,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -342,7 +342,7 @@ public class NotificationManagerService extends SystemService { private final UserProfiles mUserProfiles = new UserProfiles(); private NotificationListeners mListeners; - private NotificationAssistants mNotificationAssistants; + private NotificationAssistants mAssistants; private ConditionProviders mConditionProviders; private NotificationUsageStats mUsageStats; @@ -441,24 +441,38 @@ public class NotificationManagerService extends SystemService { } } - private void readPolicyXml(InputStream stream, boolean forRestore) + void readPolicyXml(InputStream stream, boolean forRestore) throws XmlPullParserException, NumberFormatException, IOException { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, StandardCharsets.UTF_8.name()); - - boolean saveXml = false; - while (parser.next() != END_DOCUMENT) { - mZenModeHelper.readXml(parser, forRestore); - mRankingHelper.readXml(parser, forRestore); + XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY); + boolean migratedManagedServices = false; + int outerDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) { + mZenModeHelper.readXml(parser, forRestore); + } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){ + mRankingHelper.readXml(parser, forRestore); + } // No non-system managed services are allowed on low ram devices if (!ActivityManager.isLowRamDeviceStatic()) { - saveXml |= mListeners.readXml(parser); - saveXml |= mNotificationAssistants.readXml(parser); - saveXml |= mConditionProviders.readXml(parser); + if (mListeners.getConfig().xmlTag.equals(parser.getName())) { + mListeners.readXml(parser); + migratedManagedServices = true; + } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) { + mAssistants.readXml(parser); + migratedManagedServices = true; + } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) { + mConditionProviders.readXml(parser); + migratedManagedServices = true; + } } } - if (saveXml) { + if (!migratedManagedServices) { + mListeners.migrateToXml(); + mAssistants.migrateToXml(); + mConditionProviders.migrateToXml(); savePolicyFile(); } } @@ -467,7 +481,7 @@ public class NotificationManagerService extends SystemService { if (DBG) Slog.d(TAG, "loadPolicyFile"); synchronized (mPolicyFile) { - FileInputStream infile = null; + InputStream infile = null; try { infile = mPolicyFile.openRead(); readPolicyXml(infile, false /*forRestore*/); @@ -523,7 +537,7 @@ public class NotificationManagerService extends SystemService { mZenModeHelper.writeXml(out, forBackup); mRankingHelper.writeXml(out, forBackup); mListeners.writeXml(out, forBackup); - mNotificationAssistants.writeXml(out, forBackup); + mAssistants.writeXml(out, forBackup); mConditionProviders.writeXml(out, forBackup); out.endTag(null, TAG_NOTIFICATION_POLICY); out.endDocument(); @@ -898,7 +912,7 @@ public class NotificationManagerService extends SystemService { } } mListeners.onPackagesChanged(removingPackage, pkgList, uidList); - mNotificationAssistants.onPackagesChanged(removingPackage, pkgList, uidList); + mAssistants.onPackagesChanged(removingPackage, pkgList, uidList); mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList); savePolicyFile(); @@ -970,7 +984,7 @@ public class NotificationManagerService extends SystemService { // Refresh managed services mConditionProviders.onUserSwitched(user); mListeners.onUserSwitched(user); - mNotificationAssistants.onUserSwitched(user); + mAssistants.onUserSwitched(user); mZenModeHelper.onUserSwitched(user); } else if (action.equals(Intent.ACTION_USER_ADDED)) { mUserProfiles.updateCache(context); @@ -983,7 +997,7 @@ public class NotificationManagerService extends SystemService { final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); mConditionProviders.onUserUnlocked(user); mListeners.onUserUnlocked(user); - mNotificationAssistants.onUserUnlocked(user); + mAssistants.onUserUnlocked(user); mZenModeHelper.onUserUnlocked(user); } } @@ -1231,7 +1245,7 @@ public class NotificationManagerService extends SystemService { mListeners = notificationListeners; // This is a MangedServices object that keeps track of the assistant. - mNotificationAssistants = notificationAssistants; + mAssistants = notificationAssistants; mPolicyFile = policyFile; loadPolicyFile(); @@ -1400,7 +1414,7 @@ public class NotificationManagerService extends SystemService { // bind to listener services. mSettingsObserver.observe(); mListeners.onBootPhaseAppsCanStart(); - mNotificationAssistants.onBootPhaseAppsCanStart(); + mAssistants.onBootPhaseAppsCanStart(); mConditionProviders.onBootPhaseAppsCanStart(); } } @@ -1569,7 +1583,6 @@ public class NotificationManagerService extends SystemService { Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); return ; } - final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg)); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, Binder.getCallingUid()); @@ -1928,7 +1941,7 @@ public class NotificationManagerService extends SystemService { // Listener & assistant mListeners.onPackagesChanged(true, packages, uids); - mNotificationAssistants.onPackagesChanged(true, packages, uids); + mAssistants.onPackagesChanged(true, packages, uids); // Zen mConditionProviders.onPackagesChanged(true, packages, uids); @@ -2134,8 +2147,8 @@ public class NotificationManagerService extends SystemService { long identity = Binder.clearCallingIdentity(); try { ManagedServices manager = - mNotificationAssistants.isComponentEnabledForCurrentProfiles(component) - ? mNotificationAssistants + mAssistants.isComponentEnabledForCurrentProfiles(component) + ? mAssistants : mListeners; manager.setComponentState(component, true); } finally { @@ -2255,7 +2268,7 @@ public class NotificationManagerService extends SystemService { try { synchronized (mNotificationLock) { final ManagedServiceInfo info = - mNotificationAssistants.checkServiceTokenLocked(token); + mAssistants.checkServiceTokenLocked(token); unsnoozeNotificationInt(key, info); } } finally { @@ -2788,7 +2801,7 @@ public class NotificationManagerService extends SystemService { public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { Preconditions.checkNotNull(assistant); checkCallerIsSystemOrSameApp(assistant.getPackageName()); - return mNotificationAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), + return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(), getCallingUserHandle().getIdentifier()); } @@ -2835,7 +2848,7 @@ public class NotificationManagerService extends SystemService { if (!mActivityManager.isLowRamDevice()) { mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(), userId, false, granted); - mNotificationAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), + mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(), userId, true, granted); getContext().sendBroadcastAsUser(new Intent( @@ -2854,7 +2867,7 @@ public class NotificationManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { - mNotificationAssistants.checkServiceTokenLocked(token); + mAssistants.checkServiceTokenLocked(token); int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { final NotificationRecord n = mEnqueuedNotifications.get(i); @@ -2876,7 +2889,7 @@ public class NotificationManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { - mNotificationAssistants.checkServiceTokenLocked(token); + mAssistants.checkServiceTokenLocked(token); NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); applyAdjustment(n, adjustment); } @@ -2893,7 +2906,7 @@ public class NotificationManagerService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { - mNotificationAssistants.checkServiceTokenLocked(token); + mAssistants.checkServiceTokenLocked(token); for (Adjustment adjustment : adjustments) { NotificationRecord n = mNotificationsByKey.get(adjustment.getKey()); applyAdjustment(n, adjustment); @@ -3277,7 +3290,7 @@ public class NotificationManagerService extends SystemService { } pw.println(')'); pw.println("\n Notification assistant services:"); - mNotificationAssistants.dump(pw, filter); + mAssistants.dump(pw, filter); } if (!filter.filtered || zenOnly) { @@ -3668,7 +3681,7 @@ public class NotificationManagerService extends SystemService { cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted); updateLightsLocked(); if (mSnoozeCriterionId != null) { - mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId); + mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId); mSnoozeHelper.snooze(r); } else { mSnoozeHelper.snooze(r, mDuration); @@ -3732,8 +3745,8 @@ public class NotificationManagerService extends SystemService { mRankingHelper.extractSignals(r); // tell the assistant service about the notification - if (mNotificationAssistants.isEnabled()) { - mNotificationAssistants.onNotificationEnqueued(r); + if (mAssistants.isEnabled()) { + mAssistants.onNotificationEnqueued(r); mHandler.postDelayed(new PostNotificationRunnable(r.getKey()), DELAY_FOR_ASSISTANT_TIME); } else { @@ -5242,7 +5255,7 @@ public class NotificationManagerService extends SystemService { Config c = new Config(); c.caption = "notification assistant service"; c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; - c.managedServiceTypeTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; + c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS; c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; @@ -5354,7 +5367,7 @@ public class NotificationManagerService extends SystemService { Config c = new Config(); c.caption = "notification listener"; c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; - c.managedServiceTypeTag = TAG_ENABLED_NOTIFICATION_LISTENERS; + c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS; c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index f1b83b9d55a9..9622a24a2d4d 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -20,6 +20,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; import android.app.Notification; import android.app.NotificationChannel; @@ -64,7 +65,7 @@ public class RankingHelper implements RankingConfig { private static final int XML_VERSION = 1; - private static final String TAG_RANKING = "ranking"; + static final String TAG_RANKING = "ranking"; private static final String TAG_PACKAGE = "package"; private static final String TAG_CHANNEL = "channel"; private static final String TAG_GROUP = "channelGroup"; @@ -169,7 +170,7 @@ public class RankingHelper implements RankingConfig { } if (type == XmlPullParser.START_TAG) { if (TAG_PACKAGE.equals(tag)) { - int uid = XmlUtils.safeInt(parser, ATT_UID, Record.UNKNOWN_UID); + int uid = XmlUtils.readIntAttribute(parser, ATT_UID, Record.UNKNOWN_UID); String name = parser.getAttributeValue(null, ATT_NAME); if (!TextUtils.isEmpty(name)) { if (forRestore) { @@ -182,14 +183,21 @@ public class RankingHelper implements RankingConfig { } Record r = getOrCreateRecord(name, uid, - XmlUtils.safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), - XmlUtils.safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY), - XmlUtils.safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), - XmlUtils.safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE)); - r.importance = XmlUtils.safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); - r.priority = XmlUtils.safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY); - r.visibility = XmlUtils.safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY); - r.showBadge = XmlUtils.safeBool(parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE); + XmlUtils.readIntAttribute( + parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), + XmlUtils.readIntAttribute(parser, ATT_PRIORITY, DEFAULT_PRIORITY), + XmlUtils.readIntAttribute( + parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), + XmlUtils.readBooleanAttribute( + parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE)); + r.importance = XmlUtils.readIntAttribute( + parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); + r.priority = XmlUtils.readIntAttribute( + parser, ATT_PRIORITY, DEFAULT_PRIORITY); + r.visibility = XmlUtils.readIntAttribute( + parser, ATT_VISIBILITY, DEFAULT_VISIBILITY); + r.showBadge = XmlUtils.readBooleanAttribute( + parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE); final int innerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -214,7 +222,7 @@ public class RankingHelper implements RankingConfig { if (TAG_CHANNEL.equals(tagName)) { String id = parser.getAttributeValue(null, ATT_ID); String channelName = parser.getAttributeValue(null, ATT_NAME); - int channelImportance = XmlUtils.safeInt( + int channelImportance = XmlUtils.readIntAttribute( parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) { NotificationChannel channel = new NotificationChannel(id, @@ -545,6 +553,13 @@ public class RankingHelper implements RankingConfig { existing.setDescription(channel.getDescription()); existing.setBlockableSystem(channel.isBlockableSystem()); + // Apps are allowed to downgrade channel importance if the user has not changed any + // fields on this channel yet. + if (existing.getUserLockedFields() == 0 && + channel.getImportance() < existing.getImportance()) { + existing.setImportance(channel.getImportance()); + } + updateConfig(); return; } diff --git a/services/core/java/com/android/server/notification/XmlUtils.java b/services/core/java/com/android/server/notification/XmlUtils.java deleted file mode 100644 index 831d03970fe3..000000000000 --- a/services/core/java/com/android/server/notification/XmlUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * 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 com.android.server.notification; - -import android.annotation.NonNull; -import android.text.TextUtils; - -import org.xmlpull.v1.XmlPullParser; - -class XmlUtils { - - static @NonNull String safeString(XmlPullParser parser, String att, String defValue) { - final String value = parser.getAttributeValue(null, att); - if (value == null) return defValue; - return value; - } - - static @NonNull boolean safeBool(XmlPullParser parser, String att, boolean defValue) { - final String value = parser.getAttributeValue(null, att); - if (TextUtils.isEmpty(value)) return defValue; - return Boolean.parseBoolean(value); - } - - static @NonNull int safeInt(XmlPullParser parser, String att, int defValue) { - final String val = parser.getAttributeValue(null, att); - return tryParseInt(val, defValue); - } - - private static int tryParseInt(String value, int defValue) { - if (TextUtils.isEmpty(value)) return defValue; - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return defValue; - } - } - -} 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/notification/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java index ffbd8d493899..bd65f571d20b 100644 --- a/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/notification/src/com/android/server/notification/ManagedServicesTest.java @@ -170,7 +170,7 @@ public class ManagedServicesTest extends NotificationTestCase { null); writeExpectedValuesToSettings(approvalLevel); - assertTrue(service.readXml(parser)); + service.migrateToXml(); verifyExpectedApprovedEntries(service); } @@ -182,7 +182,7 @@ public class ManagedServicesTest extends NotificationTestCase { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, approvalLevel); - assertFalse(loadXml(service)); + loadXml(service); verifyExpectedApprovedEntries(service); } @@ -239,7 +239,7 @@ public class ManagedServicesTest extends NotificationTestCase { parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); - assertFalse(service.readXml(parser)); + service.readXml(parser); verifyExpectedApprovedEntries(service); assertFalse(service.isPackageOrComponentAllowed("this.is.a.package.name", 0)); @@ -341,11 +341,8 @@ public class ManagedServicesTest extends NotificationTestCase { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, approvalLevel); - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})), - null); writeExpectedValuesToSettings(approvalLevel); - service.readXml(parser); + service.migrateToXml(); mExpectedPrimaryPackages.put(0, "another.package"); mExpectedPrimaryComponentNames.put(0, "another.package/B1"); @@ -360,11 +357,8 @@ public class ManagedServicesTest extends NotificationTestCase { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, approvalLevel); - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})), - null); writeExpectedValuesToSettings(approvalLevel); - service.readXml(parser); + service.migrateToXml(); mExpectedSecondaryComponentNames.put(10, "component/2"); mExpectedSecondaryPackages.put(10, "component"); @@ -516,9 +510,9 @@ public class ManagedServicesTest extends NotificationTestCase { assertEquals(0, service.getAllowedComponents(10).size()); } - private boolean loadXml(ManagedServices service) throws Exception { + private void loadXml(ManagedServices service) throws Exception { final StringBuffer xml = new StringBuffer(); - xml.append("<" + service.getConfig().managedServiceTypeTag + ">\n"); + xml.append("<" + service.getConfig().xmlTag + ">\n"); for (int userId : mExpectedPrimary.get(service.mApprovalLevel).keySet()) { xml.append(getXmlEntry( mExpectedPrimary.get(service.mApprovalLevel).get(userId), userId, true)); @@ -527,13 +521,13 @@ public class ManagedServicesTest extends NotificationTestCase { xml.append(getXmlEntry( mExpectedSecondary.get(service.mApprovalLevel).get(userId), userId, false)); } - xml.append("</" + service.getConfig().managedServiceTypeTag + ">"); + xml.append("</" + service.getConfig().xmlTag + ">"); XmlPullParser parser = Xml.newPullParser(); parser.setInput(new BufferedInputStream( new ByteArrayInputStream(xml.toString().getBytes())), null); parser.nextTag(); - return service.readXml(parser); + service.readXml(parser); } private void addExpectedServices(final ManagedServices service, final List<String> packages, @@ -674,7 +668,7 @@ public class ManagedServicesTest extends NotificationTestCase { @Override protected Config getConfig() { final Config c = new Config(); - c.managedServiceTypeTag= "test"; + c.xmlTag = "test"; c.secureSettingName = SETTING; c.secondarySettingName = SECONDARY_SETTING; c.bindPermission = "permission"; diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index bbc03c3aa8b7..09af1e2fd7d4 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -20,9 +20,6 @@ import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.content.pm.PackageManager.PERMISSION_DENIED; -import static com.android.server.notification.NotificationManagerService - .MESSAGE_SEND_RANKING_UPDATE; - import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -34,12 +31,10 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -60,35 +55,34 @@ import android.content.pm.ParceledListSlice; import android.graphics.Color; import android.media.AudioManager; import android.os.Binder; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; import android.os.Process; import android.os.UserHandle; import android.provider.Settings.Secure; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; +import android.service.notification.ZenModeConfig; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.util.ArrayMap; import android.util.AtomicFile; -import android.util.Log; -import android.util.Slog; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; +import com.android.server.notification.NotificationManagerService.NotificationAssistants; +import com.android.server.notification.NotificationManagerService.NotificationListeners; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -102,7 +96,7 @@ import java.util.Map; @RunWithLooper public class NotificationManagerServiceTest extends NotificationTestCase { private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; - private final int uid = Binder.getCallingUid(); + private final int mUid = Binder.getCallingUid(); private NotificationManagerService mNotificationManagerService; private INotificationManager mBinderService; private NotificationManagerInternal mInternalService; @@ -115,7 +109,6 @@ public class NotificationManagerServiceTest extends NotificationTestCase { private TestableLooper mTestableLooper; @Mock private RankingHelper mRankingHelper; - @Mock AtomicFile mPolicyFile; File mFile; @Mock @@ -129,8 +122,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase { private NotificationChannel mTestNotificationChannel = new NotificationChannel( TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT); @Mock - private NotificationManagerService.NotificationListeners mNotificationListeners; - @Mock private NotificationManagerService.NotificationAssistants mNotificationAssistants; + private NotificationListeners mListeners; + @Mock private NotificationAssistants mAssistants; @Mock private ConditionProviders mConditionProviders; private ManagedServices.ManagedServiceInfo mListener; @Mock private ICompanionDeviceManager mCompanionMgr; @@ -164,7 +157,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { // most tests assume badging is enabled Secure.putIntForUser(getContext().getContentResolver(), Secure.NOTIFICATION_BADGING, 1, - UserHandle.getUserHandleForUid(uid).getIdentifier()); + UserHandle.getUserHandleForUid(mUid).getIdentifier()); mNotificationManagerService = new TestableNotificationManagerService(mContext); @@ -173,7 +166,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mHandler = mNotificationManagerService.new WorkerHandler(mTestableLooper.getLooper()); // MockPackageManager - default returns ApplicationInfo with matching calling UID final ApplicationInfo applicationInfo = new ApplicationInfo(); - applicationInfo.uid = uid; + applicationInfo.uid = mUid; when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) @@ -182,18 +175,34 @@ public class NotificationManagerServiceTest extends NotificationTestCase { when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class)); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + // write to a test file; the system file isn't readable from tests mFile = new File(mContext.getCacheDir(), "test.xml"); mFile.createNewFile(); - when(mPolicyFile.openRead()).thenReturn(new FileInputStream(mFile)); - when(mPolicyFile.startWrite()).thenReturn(new FileOutputStream(mFile)); + final String preupgradeXml = "<notification-policy></notification-policy>"; + mPolicyFile = new AtomicFile(mFile); + FileOutputStream fos = mPolicyFile.startWrite(); + fos.write(preupgradeXml.getBytes()); + mPolicyFile.finishWrite(fos); + FileInputStream fStream = new FileInputStream(mFile); + + // Setup managed services + mListener = mListeners.new ManagedServiceInfo( + null, new ComponentName(PKG, "test_class"), mUid, true, null, 0); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + ManagedServices.Config listenerConfig = new ManagedServices.Config(); + listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS; + when(mListeners.getConfig()).thenReturn(listenerConfig); + ManagedServices.Config assistantConfig = new ManagedServices.Config(); + assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS; + when(mAssistants.getConfig()).thenReturn(assistantConfig); + ManagedServices.Config dndConfig = new ManagedServices.Config(); + dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS; + when(mConditionProviders.getConfig()).thenReturn(dndConfig); - mListener = mNotificationListeners.new ManagedServiceInfo( - null, new ComponentName(PKG, "test_class"), uid, true, null, 0); - when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); try { mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager, mPackageManagerClient, mockLightsManager, - mNotificationListeners, mNotificationAssistants, mConditionProviders, + mListeners, mAssistants, mConditionProviders, mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper); } catch (SecurityException e) { @@ -228,8 +237,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase { .setGroup(groupKey) .setGroupSummary(isSummary); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0, - nb.build(), new UserHandle(uid), null, 0); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); } private NotificationRecord generateNotificationRecord(NotificationChannel channel) { @@ -247,8 +256,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase { if (extender != null) { nb.extend(extender); } - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0, - nb.build(), new UserHandle(uid), null, 0); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); return new NotificationRecord(mContext, sbn, channel); } @@ -293,17 +302,17 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testCreateNotificationChannels_SingleChannel() throws Exception { final NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(channel))); final NotificationChannel createdChannel = - mBinderService.getNotificationChannel("test_pkg", "id"); + mBinderService.getNotificationChannel(PKG, "id"); assertTrue(createdChannel != null); } @Test public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception { try { - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(null))); fail("Exception should be thrown immediately."); } catch (NullPointerException e) { @@ -317,10 +326,10 @@ public class NotificationManagerServiceTest extends NotificationTestCase { new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT); final NotificationChannel channel2 = new NotificationChannel("id2", "name", NotificationManager.IMPORTANCE_DEFAULT); - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(channel1, channel2))); - assertTrue(mBinderService.getNotificationChannel("test_pkg", "id1") != null); - assertTrue(mBinderService.getNotificationChannel("test_pkg", "id2") != null); + assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null); + assertTrue(mBinderService.getNotificationChannel(PKG, "id2") != null); } @Test @@ -328,30 +337,71 @@ public class NotificationManagerServiceTest extends NotificationTestCase { throws Exception { final NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(channel))); // Recreating the channel doesn't throw, but ignores importance. final NotificationChannel dupeChannel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(dupeChannel))); final NotificationChannel createdChannel = - mBinderService.getNotificationChannel("test_pkg", "id"); + mBinderService.getNotificationChannel(PKG, "id"); assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance()); } @Test + public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance() + throws Exception { + final NotificationChannel channel = + new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); + mBinderService.createNotificationChannels(PKG, + new ParceledListSlice(Arrays.asList(channel))); + + // Recreating with a lower importance is allowed to modify the channel. + final NotificationChannel dupeChannel = + new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); + mBinderService.createNotificationChannels(PKG, + new ParceledListSlice(Arrays.asList(dupeChannel))); + final NotificationChannel createdChannel = + mBinderService.getNotificationChannel(PKG, "id"); + assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance()); + } + + @Test + public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated() + throws Exception { + final NotificationChannel channel = + new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); + mBinderService.createNotificationChannels(PKG, + new ParceledListSlice(Arrays.asList(channel))); + + // The user modifies importance directly, can no longer be changed by the app. + final NotificationChannel updatedChannel = + new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); + mBinderService.updateNotificationChannelForPackage(PKG, mUid, updatedChannel); + + // Recreating with a lower importance leaves channel unchanged. + final NotificationChannel dupeChannel = + new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); + mBinderService.createNotificationChannels(PKG, + new ParceledListSlice(Arrays.asList(dupeChannel))); + final NotificationChannel createdChannel = + mBinderService.getNotificationChannel(PKG, "id"); + assertEquals(NotificationManager.IMPORTANCE_HIGH, createdChannel.getImportance()); + } + + @Test public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond() throws Exception { final NotificationChannel channel1 = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); final NotificationChannel channel2 = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH); - mBinderService.createNotificationChannels("test_pkg", + mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(channel1, channel2))); final NotificationChannel createdChannel = - mBinderService.getNotificationChannel("test_pkg", "id"); + mBinderService.getNotificationChannel(PKG, "id"); assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance()); } @@ -382,7 +432,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testEnqueuedBlockedNotifications_blockedApp() throws Exception { when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); - mBinderService.setNotificationsEnabledForPackage(PKG, uid, false); + mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false); final StatusBarNotification sbn = generateNotificationRecord(null).sbn; mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", @@ -463,7 +513,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId()); waitForIdle(); - mNotificationManagerService.mNotificationDelegate.onClearAll(uid, Binder.getCallingPid(), + mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), n.getUserId()); waitForIdle(); StatusBarNotification[] notifs = @@ -605,7 +655,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mTestNotificationChannel, 1, "group", true); notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; mNotificationManagerService.addNotification(notif); - mNotificationManagerService.cancelAllNotificationsInt(uid, 0, PKG, null, 0, 0, true, + mNotificationManagerService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, true, notif.getUserId(), 0, null); waitForIdle(); StatusBarNotification[] notifs = @@ -620,7 +670,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; mNotificationManagerService.addNotification(notif); - mNotificationManagerService.mNotificationDelegate.onClearAll(uid, Binder.getCallingPid(), + mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), notif.getUserId()); waitForIdle(); StatusBarNotification[] notifs = @@ -665,7 +715,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.addNotification(child); mNotificationManagerService.addNotification(child2); mNotificationManagerService.addNotification(newGroup); - mNotificationManagerService.mNotificationDelegate.onClearAll(uid, Binder.getCallingPid(), + mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId()); waitForIdle(); StatusBarNotification[] notifs = @@ -776,7 +826,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testCreateChannelNotifyListener() throws Exception { List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mNotificationManagerService.setRankingHelper(mRankingHelper); when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) @@ -786,13 +836,13 @@ public class NotificationManagerServiceTest extends NotificationTestCase { eq(channel2.getId()), anyBoolean())) .thenReturn(channel2); - reset(mNotificationListeners); + reset(mListeners); mBinderService.createNotificationChannels(PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); - verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); - verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(channel2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -801,18 +851,18 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testCreateChannelGroupNotifyListener() throws Exception { List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mNotificationManagerService.setRankingHelper(mRankingHelper); NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b"); NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m"); - reset(mNotificationListeners); + reset(mListeners); mBinderService.createNotificationChannelGroups(PKG, new ParceledListSlice(Arrays.asList(group1, group2))); - verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), eq(Process.myUserHandle()), eq(group1), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); - verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), eq(Process.myUserHandle()), eq(group2), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); } @@ -821,16 +871,16 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testUpdateChannelNotifyListener() throws Exception { List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mNotificationManagerService.setRankingHelper(mRankingHelper); mTestNotificationChannel.setLightColor(Color.CYAN); when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) .thenReturn(mTestNotificationChannel); - reset(mNotificationListeners); + reset(mListeners); mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel); - verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -839,14 +889,14 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testDeleteChannelNotifyListener() throws Exception { List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mNotificationManagerService.setRankingHelper(mRankingHelper); when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean())) .thenReturn(mTestNotificationChannel); - reset(mNotificationListeners); + reset(mListeners); mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId()); - verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -855,14 +905,14 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testDeleteChannelGroupNotifyListener() throws Exception { List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c"); mNotificationManagerService.setRankingHelper(mRankingHelper); when(mRankingHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt())) .thenReturn(ncg); - reset(mNotificationListeners); + reset(mListeners); mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId()); - verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), + verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG), eq(Process.myUserHandle()), eq(ncg), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); } @@ -872,14 +922,14 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mBinderService.updateNotificationChannelFromPrivilegedListener( null, PKG, Process.myUserHandle(), mTestNotificationChannel); verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any()); - verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -888,7 +938,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); try { mBinderService.updateNotificationChannelFromPrivilegedListener( @@ -900,7 +950,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); - verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -910,11 +960,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mListener = mock(ManagedServices.ManagedServiceInfo.class); mListener.component = new ComponentName(PKG, PKG); when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); - when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); try { mBinderService.updateNotificationChannelFromPrivilegedListener( @@ -926,7 +976,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any()); - verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG), + verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); } @@ -936,7 +986,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mBinderService.getNotificationChannelsFromPrivilegedListener( null, PKG, Process.myUserHandle()); @@ -949,7 +999,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); try { mBinderService.getNotificationChannelsFromPrivilegedListener( @@ -968,10 +1018,10 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mListener = mock(ManagedServices.ManagedServiceInfo.class); when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); - when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); try { mBinderService.getNotificationChannelsFromPrivilegedListener( @@ -990,7 +1040,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); associations.add("a"); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mBinderService.getNotificationChannelGroupsFromPrivilegedListener( null, PKG, Process.myUserHandle()); @@ -1002,7 +1052,7 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); try { mBinderService.getNotificationChannelGroupsFromPrivilegedListener( @@ -1019,10 +1069,10 @@ public class NotificationManagerServiceTest extends NotificationTestCase { public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { mNotificationManagerService.setRankingHelper(mRankingHelper); List<String> associations = new ArrayList<>(); - when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations); + when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations); mListener = mock(ManagedServices.ManagedServiceInfo.class); when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); - when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener); + when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); try { mBinderService.getNotificationChannelGroupsFromPrivilegedListener( @@ -1191,11 +1241,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { } } - verify(mNotificationListeners, times(1)).setPackageOrComponentEnabled( + verify(mListeners, times(1)).setPackageOrComponentEnabled( c.flattenToString(), 0, true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.flattenToString(), 0, false, true); - verify(mNotificationAssistants, never()).setPackageOrComponentEnabled( + verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1210,11 +1260,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { } } - verify(mNotificationAssistants, times(1)).setPackageOrComponentEnabled( + verify(mAssistants, times(1)).setPackageOrComponentEnabled( c.flattenToString(), 0, true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.flattenToString(), 0, false, true); - verify(mNotificationListeners, never()).setPackageOrComponentEnabled( + verify(mListeners, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1231,9 +1281,9 @@ public class NotificationManagerServiceTest extends NotificationTestCase { verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.getPackageName(), 0, true, true); - verify(mNotificationAssistants, never()).setPackageOrComponentEnabled( + verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); - verify(mNotificationListeners, never()).setPackageOrComponentEnabled( + verify(mListeners, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1243,11 +1293,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { ComponentName c = ComponentName.unflattenFromString("package/Component"); mBinderService.setNotificationListenerAccessGranted(c, true); - verify(mNotificationListeners, never()).setPackageOrComponentEnabled( + verify(mListeners, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, true, true); verify(mConditionProviders, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, false, true); - verify(mNotificationAssistants, never()).setPackageOrComponentEnabled( + verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1258,11 +1308,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mBinderService.setNotificationAssistantAccessGranted(c, true); - verify(mNotificationListeners, never()).setPackageOrComponentEnabled( + verify(mListeners, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, true, true); verify(mConditionProviders, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, false, true); - verify(mNotificationAssistants, never()).setPackageOrComponentEnabled( + verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1272,11 +1322,11 @@ public class NotificationManagerServiceTest extends NotificationTestCase { ComponentName c = ComponentName.unflattenFromString("package/Component"); mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); - verify(mNotificationListeners, never()).setPackageOrComponentEnabled( + verify(mListeners, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, true, true); verify(mConditionProviders, never()).setPackageOrComponentEnabled( c.flattenToString(), 0, false, true); - verify(mNotificationAssistants, never()).setPackageOrComponentEnabled( + verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -1333,8 +1383,8 @@ public class NotificationManagerServiceTest extends NotificationTestCase { .setColorized(true) .setFlag(Notification.FLAG_CAN_COLORIZE, true) .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0, - nb.build(), new UserHandle(uid), null, 0); + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); mBinderService.enqueueNotificationWithTag(PKG, PKG, null, @@ -1350,11 +1400,13 @@ public class NotificationManagerServiceTest extends NotificationTestCase { @Test public void testGetNotificationCountLocked() throws Exception { for (int i = 0; i < 20; i++) { - NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); + NotificationRecord r = + generateNotificationRecord(mTestNotificationChannel, i, null, false); mNotificationManagerService.addEnqueuedNotification(r); } for (int i = 0; i < 20; i++) { - NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); + NotificationRecord r = + generateNotificationRecord(mTestNotificationChannel, i, null, false); mNotificationManagerService.addNotification(r); } @@ -1364,15 +1416,15 @@ public class NotificationManagerServiceTest extends NotificationTestCase { .setSmallIcon(android.R.drawable.sym_def_app_icon) .build(); - StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", uid, 0, - n, new UserHandle(uid), null, 0); + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0, + n, new UserHandle(mUid), null, 0); NotificationRecord otherPackage = new NotificationRecord(mContext, sbn, mTestNotificationChannel); mNotificationManagerService.addEnqueuedNotification(otherPackage); mNotificationManagerService.addNotification(otherPackage); // Same notifications are enqueued as posted, everything counts b/c id and tag don't match - int userId = new UserHandle(uid).getIdentifier(); + int userId = new UserHandle(mUid).getIdentifier(); assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null)); assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2")); assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana")); @@ -1452,4 +1504,50 @@ public class NotificationManagerServiceTest extends NotificationTestCase { mNotificationManagerService.handleRankingSort(); verify(handler, never()).scheduleSendRankingUpdate(); } + + @Test + public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception { + final String preupgradeXml = "<notification-policy version=\"1\">" + + "<zen></zen>" + + "<ranking></ranking>" + + "<enabled_listeners>" + + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" + + "</enabled_listeners>" + + "<enabled_assistants>" + + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" + + "</enabled_assistants>" + + "<dnd_apps>" + + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" + + "</dnd_apps>" + + "</notification-policy>"; + mNotificationManagerService.readPolicyXml( + new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), false); + verify(mListeners, times(1)).readXml(any()); + verify(mConditionProviders, times(1)).readXml(any()); + verify(mAssistants, times(1)).readXml(any()); + + // numbers are inflated for setup + verify(mListeners, times(1)).migrateToXml(); + verify(mConditionProviders, times(1)).migrateToXml(); + verify(mAssistants, times(1)).migrateToXml(); + } + + @Test + public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception { + final String preupgradeXml = "<notification-policy version=\"1\">" + + "<zen></zen>" + + "<ranking></ranking>" + + "</notification-policy>"; + mNotificationManagerService.readPolicyXml( + new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), false); + verify(mListeners, never()).readXml(any()); + verify(mConditionProviders, never()).readXml(any()); + verify(mAssistants, never()).readXml(any()); + + // numbers are inflated for setup + verify(mListeners, times(2)).migrateToXml(); + verify(mConditionProviders, times(2)).migrateToXml(); + verify(mAssistants, times(2)).migrateToXml(); + } + } 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/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java index 984a484dadc2..ea207f1f1910 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java +++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java @@ -58,7 +58,7 @@ public class TaskPersisterTest extends AndroidTestCase { } public void testTaskIdsPersistence() { - SparseBooleanArray taskIdsOnFile = mTaskPersister.loadPersistedTaskIdsForUser(testUserId); + SparseBooleanArray taskIdsOnFile = new SparseBooleanArray(); for (int i = 0; i < 100; i++) { taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true); } 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/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 765c73beedf4..216d28cb49ba 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -2788,6 +2788,13 @@ public final class Telephony { public static final String USER_VISIBLE = "user_visible"; /** + * Is the user allowed to edit this APN? + * <p>Type: INTEGER (boolean) </p> + * @hide + */ + public static final String USER_EDITABLE = "user_editable"; + + /** * Following are possible values for the EDITED field * @hide */ 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(); + } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 0d4359e878d2..8075e178f2ed 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -41,6 +41,8 @@ import android.util.Log; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import dalvik.system.CloseGuard; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -668,15 +670,21 @@ public class WifiP2pManager { * Most p2p operations require a Channel as an argument. An instance of Channel is obtained * by doing a call on {@link #initialize} */ - public static class Channel { - Channel(Context context, Looper looper, ChannelListener l, Binder binder) { + public static class Channel implements AutoCloseable { + /** @hide */ + public Channel(Context context, Looper looper, ChannelListener l, Binder binder, + WifiP2pManager p2pManager) { mAsyncChannel = new AsyncChannel(); mHandler = new P2pHandler(looper); mChannelListener = l; mContext = context; mBinder = binder; + mP2pManager = p2pManager; + + mCloseGuard.open("close"); } private final static int INVALID_LISTENER_KEY = 0; + private final WifiP2pManager mP2pManager; private ChannelListener mChannelListener; private ServiceResponseListener mServRspListener; private DnsSdServiceResponseListener mDnsSdServRspListener; @@ -686,6 +694,41 @@ public class WifiP2pManager { private final Object mListenerMapLock = new Object(); private int mListenerKey = 0; + private final CloseGuard mCloseGuard = CloseGuard.get(); + + /** + * Close the current P2P connection and indicate to the P2P service that connections + * created by the app can be removed. + */ + public void close() { + if (mP2pManager == null) { + Log.w(TAG, "Channel.close(): Null mP2pManager!?"); + } else { + try { + mP2pManager.mService.close(mBinder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + mAsyncChannel.disconnect(); + mCloseGuard.close(); + } + + /** @hide */ + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + close(); + } finally { + super.finalize(); + } + } + /* package */ final Binder mBinder; private AsyncChannel mAsyncChannel; @@ -913,11 +956,12 @@ public class WifiP2pManager { Messenger messenger, Binder binder) { if (messenger == null) return null; - Channel c = new Channel(srcContext, srcLooper, listener, binder); + Channel c = new Channel(srcContext, srcLooper, listener, binder, this); if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger) == AsyncChannel.STATUS_SUCCESSFUL) { return c; } else { + c.close(); return null; } } @@ -1422,24 +1466,6 @@ public class WifiP2pManager { } /** - * Close the current P2P connection and clean-up any configuration requested by the - * current app. Takes same action as taken when the app dies. - * - * @param c is the channel created at {@link #initialize} - * - * @hide - */ - public void close(Channel c) { - try { - if (c != null) { - mService.close(c.mBinder); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Get a handover request message for use in WFA NFC Handover transfer. * @hide */ diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk index 8dc244f086cc..afab1a3721db 100644 --- a/wifi/tests/Android.mk +++ b/wifi/tests/Android.mk @@ -50,6 +50,7 @@ LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ + core-test-rules \ guava \ mockito-target-minus-junit4 \ frameworks-base-testutils \ diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java new file mode 100644 index 000000000000..1e8382f9b045 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java @@ -0,0 +1,82 @@ +/* + * 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.net.wifi.p2p; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.test.TestLooper; + +import libcore.junit.util.ResourceLeakageDetector; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Unit test harness for WifiP2pManager. + */ +public class WifiP2pManagerTest { + private WifiP2pManager mDut; + private TestLooper mTestLooper; + + @Mock + public Context mContextMock; + @Mock + IWifiP2pManager mP2pServiceMock; + + @Rule + public ResourceLeakageDetector.LeakageDetectorRule leakageDetectorRule = + ResourceLeakageDetector.getRule(); + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mDut = new WifiP2pManager(mP2pServiceMock); + mTestLooper = new TestLooper(); + } + + /** + * Validate that on finalize we close the channel and flag a resource leakage. + */ + @Test + public void testChannelFinalize() throws Exception { + WifiP2pManager.Channel channel = new WifiP2pManager.Channel(mContextMock, + mTestLooper.getLooper(), null, null, mDut); + + leakageDetectorRule.assertUnreleasedResourceCount(channel, 1); + } + + /** + * Validate that when close is called on a channel it frees up resources (i.e. don't + * get flagged again on finalize). + */ + @Test + public void testChannelClose() throws Exception { + WifiP2pManager.Channel channel = new WifiP2pManager.Channel(mContextMock, + mTestLooper.getLooper(), null, null, mDut); + + channel.close(); + verify(mP2pServiceMock).close(any()); + + leakageDetectorRule.assertUnreleasedResourceCount(channel, 0); + } +} |