diff options
182 files changed, 2917 insertions, 1700 deletions
diff --git a/Android.mk b/Android.mk index 0e5dfed53607..337faef406d9 100644 --- a/Android.mk +++ b/Android.mk @@ -944,27 +944,8 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -werror -hide 111 -hide 113 \ -overview $(LOCAL_PATH)/core/java/overview.html -SUPPORT_API_DIR := ./frameworks/support/api - -# More API Level information for the Support Library, which is currently -# included as part of the core framework docs build. -framework_docs_LOCAL_DROIDDOC_OPTIONS += \ - -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \ - -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \ - -since $(SUPPORT_API_DIR)/22.1.0.txt 22.1.0 \ - -since $(SUPPORT_API_DIR)/22.2.0.txt 22.2.0 \ - -since $(SUPPORT_API_DIR)/22.2.1.txt 22.2.1 \ - -since $(SUPPORT_API_DIR)/23.0.0.txt 23.0.0 \ - -since $(SUPPORT_API_DIR)/23.1.0.txt 23.1.0 \ - -since $(SUPPORT_API_DIR)/23.1.1.txt 23.1.1 \ - -since $(SUPPORT_API_DIR)/23.2.0.txt 23.2.0 \ - -since $(SUPPORT_API_DIR)/23.2.1.txt 23.2.1 \ - -since $(SUPPORT_API_DIR)/23.4.0.txt 23.4.0 \ - -since $(SUPPORT_API_DIR)/24.0.0.txt 24.0.0 \ - -since $(SUPPORT_API_DIR)/24.1.0.txt 24.1.0 \ - -since $(SUPPORT_API_DIR)/24.2.0.txt 24.2.0 \ - -since $(SUPPORT_API_DIR)/25.0.0.txt 25.0.0 \ - -since $(SUPPORT_API_DIR)/25.1.0.txt 25.1.0 +# Allow the support library to add its own droiddoc options. +include $(LOCAL_PATH)/../support/droiddoc.mk framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \ $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON) diff --git a/api/current.txt b/api/current.txt index a4893f9ed378..227601205369 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5415,6 +5415,7 @@ package android.app { ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); method public java.lang.String getDataMimeType(); method public android.net.Uri getDataUri(); + method public android.os.Bundle getExtras(); method public java.lang.CharSequence getSender(); method public java.lang.CharSequence getText(); method public long getTimestamp(); @@ -5494,7 +5495,6 @@ package android.app { public final class NotificationChannel implements android.os.Parcelable { ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); - ctor public NotificationChannel(java.lang.String, int, int); ctor protected NotificationChannel(android.os.Parcel); method public boolean canBypassDnd(); method public boolean canShowBadge(); @@ -5508,7 +5508,6 @@ package android.app { method public int getLightColor(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); method public void setBypassDnd(boolean); @@ -5516,6 +5515,7 @@ package android.app { method public void setImportance(int); method public void setLightColor(int); method public void setLockscreenVisibility(int); + method public void setName(java.lang.CharSequence); method public void setShowBadge(boolean); method public void setSound(android.net.Uri, android.media.AudioAttributes); method public void setVibrationPattern(long[]); @@ -5528,14 +5528,12 @@ package android.app { public final class NotificationChannelGroup implements android.os.Parcelable { ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); - ctor public NotificationChannelGroup(java.lang.String, int); ctor protected NotificationChannelGroup(android.os.Parcel); method public android.app.NotificationChannelGroup clone(); method public int describeContents(); method public java.util.List<android.app.NotificationChannel> getChannels(); method public java.lang.String getId(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; } @@ -5551,12 +5549,14 @@ package android.app { method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>); method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(); method public java.util.List<android.app.NotificationChannel> getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); @@ -5718,6 +5718,8 @@ package android.app { method public java.lang.CharSequence getContentDescription(); method public android.graphics.drawable.Icon getIcon(); method public java.lang.CharSequence getTitle(); + method public boolean isEnabled(); + method public void setEnabled(boolean); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR; } @@ -7123,6 +7125,7 @@ package android.bluetooth { method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner(); method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices(); method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter(); + method public int getLeMaximumAdvertisingDataLength(); method public java.lang.String getName(); method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager(); method public int getProfileConnectionState(int); @@ -10673,6 +10676,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking"; field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance"; field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute"; @@ -12758,7 +12762,7 @@ package android.graphics { } public class ColorFilter { - ctor public ColorFilter(); + ctor public deprecated ColorFilter(); } public class ColorMatrix { @@ -12782,6 +12786,9 @@ package android.graphics { public class ColorMatrixColorFilter extends android.graphics.ColorFilter { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); + method public void getColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -13005,6 +13012,10 @@ package android.graphics { public class LightingColorFilter extends android.graphics.ColorFilter { ctor public LightingColorFilter(int, int); + method public int getColorAdd(); + method public int getColorMultiply(); + method public void setColorAdd(int); + method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { @@ -13521,6 +13532,10 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); + method public int getColor(); + method public android.graphics.PorterDuff.Mode getMode(); + method public void setColor(int); + method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -37158,11 +37173,11 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final int REASON_APP_CANCEL = 8; // 0x8 field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CANCEL = 2; // 0x2 + field public static final int REASON_CANCEL_ALL = 3; // 0x3 field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 - field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 - field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 - field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 - field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_CLICK = 1; // 0x1 + field public static final int REASON_ERROR = 4; // 0x4 field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_LISTENER_CANCEL = 10; // 0xa @@ -45076,8 +45091,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofill(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); @@ -46292,7 +46307,7 @@ package android.view { method public abstract int addChildCount(int); method public abstract void asyncCommit(); method public abstract android.view.ViewStructure asyncNewChild(int); - method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure asyncNewChild(int, int, int); method public abstract int getChildCount(); method public abstract android.os.Bundle getExtras(); method public abstract java.lang.CharSequence getHint(); @@ -46301,7 +46316,7 @@ package android.view { method public abstract int getTextSelectionStart(); method public abstract boolean hasExtras(); method public abstract android.view.ViewStructure newChild(int); - method public abstract android.view.ViewStructure newChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure newChild(int, int, int); method public abstract void setAccessibilityFocused(boolean); method public abstract void setActivated(boolean); method public abstract void setAlpha(float); @@ -47573,11 +47588,11 @@ package android.view.autofill { method public void commit(); method public boolean isEnabled(); method public void notifyValueChanged(android.view.View); + method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue); method public void notifyViewEntered(android.view.View); + method public void notifyViewEntered(android.view.View, int, android.graphics.Rect); method public void notifyViewExited(android.view.View); - method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue); - method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect); - method public void notifyVirtualViewExited(android.view.View, int); + method public void notifyViewExited(android.view.View, int); method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(android.view.View); method public void requestAutofill(android.view.View, int, android.graphics.Rect); @@ -47590,9 +47605,10 @@ package android.view.autofill { public static abstract class AutofillManager.AutofillCallback { ctor public AutofillManager.AutofillCallback(); method public void onAutofillEvent(android.view.View, int); - method public void onAutofillEventVirtual(android.view.View, int, int); + method public void onAutofillEvent(android.view.View, int, int); field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2 field public static final int EVENT_INPUT_SHOWN = 1; // 0x1 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index cf4902c4e18d..ae510c9c24b9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5589,6 +5589,7 @@ package android.app { ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); method public java.lang.String getDataMimeType(); method public android.net.Uri getDataUri(); + method public android.os.Bundle getExtras(); method public java.lang.CharSequence getSender(); method public java.lang.CharSequence getText(); method public long getTimestamp(); @@ -5681,7 +5682,6 @@ package android.app { public final class NotificationChannel implements android.os.Parcelable { ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); - ctor public NotificationChannel(java.lang.String, int, int); ctor protected NotificationChannel(android.os.Parcel); method public boolean canBypassDnd(); method public boolean canShowBadge(); @@ -5695,19 +5695,17 @@ package android.app { method public int getLightColor(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public android.net.Uri getSound(); method public int getUserLockedFields(); method public long[] getVibrationPattern(); method public boolean isDeleted(); - method public void lockFields(int); method public void populateFromXml(org.xmlpull.v1.XmlPullParser); method public void setBypassDnd(boolean); - method public void setDeleted(boolean); method public void setGroup(java.lang.String); method public void setImportance(int); method public void setLightColor(int); method public void setLockscreenVisibility(int); + method public void setName(java.lang.CharSequence); method public void setShowBadge(boolean); method public void setSound(android.net.Uri, android.media.AudioAttributes); method public void setVibrationPattern(long[]); @@ -5732,18 +5730,14 @@ package android.app { public final class NotificationChannelGroup implements android.os.Parcelable { ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); - ctor public NotificationChannelGroup(java.lang.String, int); ctor protected NotificationChannelGroup(android.os.Parcel); - method public void addChannel(android.app.NotificationChannel); method public android.app.NotificationChannelGroup clone(); method public int describeContents(); method public java.util.List<android.app.NotificationChannel> getChannels(); method public java.lang.String getId(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public org.json.JSONObject toJson() throws org.json.JSONException; method public void writeToParcel(android.os.Parcel, int); - method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException; field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; } @@ -5758,12 +5752,14 @@ package android.app { method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>); method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(); method public java.util.List<android.app.NotificationChannel> getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); @@ -5925,6 +5921,8 @@ package android.app { method public java.lang.CharSequence getContentDescription(); method public android.graphics.drawable.Icon getIcon(); method public java.lang.CharSequence getTitle(); + method public boolean isEnabled(); + method public void setEnabled(boolean); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR; } @@ -7596,6 +7594,7 @@ package android.bluetooth { method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner(); method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices(); method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter(); + method public int getLeMaximumAdvertisingDataLength(); method public java.lang.String getName(); method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager(); method public int getProfileConnectionState(int); @@ -11335,6 +11334,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking"; field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance"; field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute"; @@ -13496,7 +13496,7 @@ package android.graphics { } public class ColorFilter { - ctor public ColorFilter(); + ctor public deprecated ColorFilter(); } public class ColorMatrix { @@ -13520,6 +13520,9 @@ package android.graphics { public class ColorMatrixColorFilter extends android.graphics.ColorFilter { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); + method public void getColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -13743,6 +13746,10 @@ package android.graphics { public class LightingColorFilter extends android.graphics.ColorFilter { ctor public LightingColorFilter(int, int); + method public int getColorAdd(); + method public int getColorMultiply(); + method public void setColorAdd(int); + method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { @@ -14259,6 +14266,10 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); + method public int getColor(); + method public android.graphics.PorterDuff.Mode getMode(); + method public void setColor(int); + method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -34422,6 +34433,7 @@ package android.os { method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); + field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking"; field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; @@ -40233,11 +40245,11 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final int REASON_APP_CANCEL = 8; // 0x8 field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CANCEL = 2; // 0x2 + field public static final int REASON_CANCEL_ALL = 3; // 0x3 field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 - field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 - field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 - field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 - field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_CLICK = 1; // 0x1 + field public static final int REASON_ERROR = 4; // 0x4 field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_LISTENER_CANCEL = 10; // 0xa @@ -48543,8 +48555,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofill(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); @@ -49759,7 +49771,7 @@ package android.view { method public abstract int addChildCount(int); method public abstract void asyncCommit(); method public abstract android.view.ViewStructure asyncNewChild(int); - method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure asyncNewChild(int, int, int); method public abstract int getChildCount(); method public abstract android.os.Bundle getExtras(); method public abstract java.lang.CharSequence getHint(); @@ -49768,7 +49780,7 @@ package android.view { method public abstract int getTextSelectionStart(); method public abstract boolean hasExtras(); method public abstract android.view.ViewStructure newChild(int); - method public abstract android.view.ViewStructure newChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure newChild(int, int, int); method public abstract void setAccessibilityFocused(boolean); method public abstract void setActivated(boolean); method public abstract void setAlpha(float); @@ -51043,11 +51055,11 @@ package android.view.autofill { method public void commit(); method public boolean isEnabled(); method public void notifyValueChanged(android.view.View); + method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue); method public void notifyViewEntered(android.view.View); + method public void notifyViewEntered(android.view.View, int, android.graphics.Rect); method public void notifyViewExited(android.view.View); - method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue); - method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect); - method public void notifyVirtualViewExited(android.view.View, int); + method public void notifyViewExited(android.view.View, int); method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(android.view.View); method public void requestAutofill(android.view.View, int, android.graphics.Rect); @@ -51060,9 +51072,10 @@ package android.view.autofill { public static abstract class AutofillManager.AutofillCallback { ctor public AutofillManager.AutofillCallback(); method public void onAutofillEvent(android.view.View, int); - method public void onAutofillEventVirtual(android.view.View, int, int); + method public void onAutofillEvent(android.view.View, int, int); field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2 field public static final int EVENT_INPUT_SHOWN = 1; // 0x1 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/api/test-current.txt b/api/test-current.txt index e1434a280ecf..e58f4321c930 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5425,6 +5425,7 @@ package android.app { ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence); method public java.lang.String getDataMimeType(); method public android.net.Uri getDataUri(); + method public android.os.Bundle getExtras(); method public java.lang.CharSequence getSender(); method public java.lang.CharSequence getText(); method public long getTimestamp(); @@ -5504,7 +5505,6 @@ package android.app { public final class NotificationChannel implements android.os.Parcelable { ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); - ctor public NotificationChannel(java.lang.String, int, int); ctor protected NotificationChannel(android.os.Parcel); method public boolean canBypassDnd(); method public boolean canShowBadge(); @@ -5518,7 +5518,6 @@ package android.app { method public int getLightColor(); method public int getLockscreenVisibility(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); method public void setBypassDnd(boolean); @@ -5526,6 +5525,7 @@ package android.app { method public void setImportance(int); method public void setLightColor(int); method public void setLockscreenVisibility(int); + method public void setName(java.lang.CharSequence); method public void setShowBadge(boolean); method public void setSound(android.net.Uri, android.media.AudioAttributes); method public void setVibrationPattern(long[]); @@ -5538,14 +5538,12 @@ package android.app { public final class NotificationChannelGroup implements android.os.Parcelable { ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); - ctor public NotificationChannelGroup(java.lang.String, int); ctor protected NotificationChannelGroup(android.os.Parcel); method public android.app.NotificationChannelGroup clone(); method public int describeContents(); method public java.util.List<android.app.NotificationChannel> getChannels(); method public java.lang.String getId(); method public java.lang.CharSequence getName(); - method public int getNameResId(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; } @@ -5561,6 +5559,7 @@ package android.app { method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>); method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>); method public void deleteNotificationChannel(java.lang.String); + method public void deleteNotificationChannelGroup(java.lang.String); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules(); @@ -5568,6 +5567,7 @@ package android.app { method public android.content.ComponentName getEffectsSuppressor(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(java.lang.String); + method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(); method public java.util.List<android.app.NotificationChannel> getNotificationChannels(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); @@ -5729,6 +5729,8 @@ package android.app { method public java.lang.CharSequence getContentDescription(); method public android.graphics.drawable.Icon getIcon(); method public java.lang.CharSequence getTitle(); + method public boolean isEnabled(); + method public void setEnabled(boolean); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.RemoteAction> CREATOR; } @@ -7150,6 +7152,7 @@ package android.bluetooth { method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner(); method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices(); method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter(); + method public int getLeMaximumAdvertisingDataLength(); method public java.lang.String getName(); method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager(); method public int getProfileConnectionState(int); @@ -10709,6 +10712,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; + field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking"; field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode"; field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance"; field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute"; @@ -12796,7 +12800,7 @@ package android.graphics { } public class ColorFilter { - ctor public ColorFilter(); + ctor public deprecated ColorFilter(); } public class ColorMatrix { @@ -12820,6 +12824,9 @@ package android.graphics { public class ColorMatrixColorFilter extends android.graphics.ColorFilter { ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix); ctor public ColorMatrixColorFilter(float[]); + method public void getColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrix(android.graphics.ColorMatrix); + method public void setColorMatrixArray(float[]); } public abstract class ColorSpace { @@ -13043,6 +13050,10 @@ package android.graphics { public class LightingColorFilter extends android.graphics.ColorFilter { ctor public LightingColorFilter(int, int); + method public int getColorAdd(); + method public int getColorMultiply(); + method public void setColorAdd(int); + method public void setColorMultiply(int); } public class LinearGradient extends android.graphics.Shader { @@ -13559,6 +13570,10 @@ package android.graphics { public class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); + method public int getColor(); + method public android.graphics.PorterDuff.Mode getMode(); + method public void setColor(int); + method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -31720,6 +31735,7 @@ package android.os { method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); + field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking"; field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; @@ -37335,11 +37351,11 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final int REASON_APP_CANCEL = 8; // 0x8 field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9 + field public static final int REASON_CANCEL = 2; // 0x2 + field public static final int REASON_CANCEL_ALL = 3; // 0x3 field public static final int REASON_CHANNEL_BANNED = 17; // 0x11 - field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2 - field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3 - field public static final int REASON_DELEGATE_CLICK = 1; // 0x1 - field public static final int REASON_DELEGATE_ERROR = 4; // 0x4 + field public static final int REASON_CLICK = 1; // 0x1 + field public static final int REASON_ERROR = 4; // 0x4 field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc field public static final int REASON_LISTENER_CANCEL = 10; // 0xa @@ -45437,8 +45453,8 @@ package android.view { method public void addTouchables(java.util.ArrayList<android.view.View>); method public android.view.ViewPropertyAnimator animate(); method public void announceForAccessibility(java.lang.CharSequence); - method public void autofill(android.view.autofill.AutofillValue); - method public void autofillVirtual(int, android.view.autofill.AutofillValue); + method public boolean autofill(android.view.autofill.AutofillValue); + method public boolean autofill(int, android.view.autofill.AutofillValue); method protected boolean awakenScrollBars(); method protected boolean awakenScrollBars(int); method protected boolean awakenScrollBars(int, boolean); @@ -46660,7 +46676,7 @@ package android.view { method public abstract int addChildCount(int); method public abstract void asyncCommit(); method public abstract android.view.ViewStructure asyncNewChild(int); - method public abstract android.view.ViewStructure asyncNewChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure asyncNewChild(int, int, int); method public abstract int getChildCount(); method public abstract android.os.Bundle getExtras(); method public abstract java.lang.CharSequence getHint(); @@ -46669,7 +46685,7 @@ package android.view { method public abstract int getTextSelectionStart(); method public abstract boolean hasExtras(); method public abstract android.view.ViewStructure newChild(int); - method public abstract android.view.ViewStructure newChildForAutofill(int, int, int); + method public abstract android.view.ViewStructure newChild(int, int, int); method public abstract void setAccessibilityFocused(boolean); method public abstract void setActivated(boolean); method public abstract void setAlpha(float); @@ -47943,11 +47959,11 @@ package android.view.autofill { method public void commit(); method public boolean isEnabled(); method public void notifyValueChanged(android.view.View); + method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue); method public void notifyViewEntered(android.view.View); + method public void notifyViewEntered(android.view.View, int, android.graphics.Rect); method public void notifyViewExited(android.view.View); - method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue); - method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect); - method public void notifyVirtualViewExited(android.view.View, int); + method public void notifyViewExited(android.view.View, int); method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback); method public void requestAutofill(android.view.View); method public void requestAutofill(android.view.View, int, android.graphics.Rect); @@ -47960,9 +47976,10 @@ package android.view.autofill { public static abstract class AutofillManager.AutofillCallback { ctor public AutofillManager.AutofillCallback(); method public void onAutofillEvent(android.view.View, int); - method public void onAutofillEventVirtual(android.view.View, int, int); + method public void onAutofillEvent(android.view.View, int, int); field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2 field public static final int EVENT_INPUT_SHOWN = 1; // 0x1 + field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3 } public final class AutofillValue implements android.os.Parcelable { diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index e5df278f2cc1..75d4f32055e2 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -21,8 +21,11 @@ import static android.Manifest.permission.GET_ACCOUNTS; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; import android.annotation.Size; import android.annotation.SystemApi; +import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.BroadcastBehavior; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -335,6 +338,8 @@ public class AccountManager { * * @deprecated use #addOnAccountsUpdatedListener to get account updates in runtime. */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(includeBackground = true) public static final String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED"; diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 86adbb002dc4..5c7a12cf5eb9 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -431,31 +431,28 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // Force all the animations to end when the duration scale is 0. private void forceToEnd() { - if (mEndCanBeCalled) { - end(); + // TODO: Below is commented out to temp work around b/36241584, uncomment this when it's + // fixed. +// if (mEndCanBeCalled) { +// end(); +// return; +// } + + // Note: we don't want to combine this case with the end() method below because in + // the case of developer calling end(), we still need to make sure end() is explicitly + // called on the child animators to maintain the old behavior. + if (mReversing) { + handleAnimationEvents(mLastEventId, 0, getTotalDuration()); } else { - // Note: we don't want to combine this case with the end() method below because in - // the case of developer calling end(), we still need to make sure end() is explicitly - // called on the child animators to maintain the old behavior. - if (mReversing) { - mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId; - for (int j = mLastEventId - 1; j >= 0; j--) { - AnimationEvent event = mEvents.get(j); - if (event.mEvent == AnimationEvent.ANIMATION_END) { - event.mNode.mAnimation.reverse(); - } - } - } else { - for (int j = mLastEventId + 1; j < mEvents.size(); j++) { - AnimationEvent event = mEvents.get(j); - if (event.mEvent == AnimationEvent.ANIMATION_START) { - event.mNode.mAnimation.start(); - } - } + long zeroScalePlayTime = getTotalDuration(); + if (zeroScalePlayTime == DURATION_INFINITE) { + // Use a large number for the play time. + zeroScalePlayTime = Integer.MAX_VALUE; } - mPlayingSet.clear(); - endAnimation(); + handleAnimationEvents(mLastEventId, mEvents.size() - 1, zeroScalePlayTime); } + mPlayingSet.clear(); + endAnimation(); } /** @@ -730,7 +727,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim if (isEmptySet) { // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the // onAnimationEnd() right away. - forceToEnd(); + end(); } } @@ -1130,8 +1127,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ private void pulseFrame(Node node, long animPlayTime) { if (!node.mEnded) { + float durationScale = ValueAnimator.getDurationScale(); + durationScale = durationScale == 0 ? 1 : durationScale; node.mEnded = node.mAnimation.pulseAnimationFrame( - (long) (animPlayTime * ValueAnimator.getDurationScale())); + (long) (animPlayTime * durationScale)); } } diff --git a/core/java/android/annotation/BroadcastBehavior.java b/core/java/android/annotation/BroadcastBehavior.java new file mode 100644 index 000000000000..9b2ca3120290 --- /dev/null +++ b/core/java/android/annotation/BroadcastBehavior.java @@ -0,0 +1,56 @@ +/* + * 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.annotation; + +import android.content.Intent; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Description of how the annotated broadcast action behaves. + * + * @hide + */ +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.SOURCE) +public @interface BroadcastBehavior { + /** + * This broadcast will only be delivered to an explicit target. + * + * @see Intent#setPackage(String) + * @see Intent#setComponent(android.content.ComponentName) + */ + boolean explicitOnly() default false; + + /** + * This broadcast will only be delivered to registered receivers. + * + * @see Intent#FLAG_RECEIVER_REGISTERED_ONLY + */ + boolean registeredOnly() default false; + + /** + * This broadcast will include all {@code AndroidManifest.xml} receivers + * regardless of process state. + * + * @see Intent#FLAG_RECEIVER_INCLUDE_BACKGROUND + */ + boolean includeBackground() default false; +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 78c29e840b9a..37a11ec6416b 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -16,6 +16,7 @@ package android.app; +import android.metrics.LogMaker; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; @@ -23,6 +24,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ToolbarActionBar; import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.policy.PhoneWindow; import android.annotation.CallSuper; @@ -765,6 +768,7 @@ public class Activity extends ContextThemeWrapper /*package*/ Configuration mCurrentConfig; private SearchManager mSearchManager; private MenuInflater mMenuInflater; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); static final class NonConfigurationInstances { Object activity; @@ -7188,6 +7192,8 @@ public class Activity extends ContextThemeWrapper public void autofill(List<AutofillId> ids, List<AutofillValue> values) { final View root = getWindow().getDecorView(); final int itemCount = ids.size(); + int numApplied = 0; + for (int i = 0; i < itemCount; i++) { final AutofillId id = ids.get(i); final AutofillValue value = values.get(i); @@ -7197,12 +7203,22 @@ public class Activity extends ContextThemeWrapper Log.w(TAG, "autofill(): no View with id " + viewId); continue; } + final boolean wasApplied; if (id.isVirtual()) { - view.autofillVirtual(id.getVirtualChildId(), value); + wasApplied = view.autofill(id.getVirtualChildId(), value); } else { - view.autofill(value); + wasApplied = view.autofill(value); + } + + if (wasApplied) { + numApplied++; } } + + LogMaker log = new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_DATASET_APPLIED); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, itemCount); + log.addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_VIEWS_FILLED, numApplied); + mMetricsLogger.write(log); } /** @hide */ diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 5cdfb8e3414e..6b53cd841dff 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -149,6 +149,7 @@ import libcore.io.DropBox; import libcore.io.EventLogger; import libcore.io.IoUtils; import libcore.net.event.NetworkEventDispatcher; +import dalvik.system.BaseDexClassLoader; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import dalvik.system.VMRuntime; @@ -336,6 +337,8 @@ public final class ActivityThread { Configuration overrideConfig; // Used for consolidating configs before sending on to Activity. private Configuration tmpConfig = new Configuration(); + // Callback used for updating activity override config. + ViewRootImpl.ActivityConfigCallback configCallback; ActivityClientRecord nextIdle; ProfilerInfo profilerInfo; @@ -371,6 +374,14 @@ public final class ActivityThread { stopped = false; hideForNow = false; nextIdle = null; + configCallback = (Configuration overrideConfig, int newDisplayId) -> { + if (activity == null) { + throw new IllegalStateException( + "Received config update for non-existing activity"); + } + activity.mMainThread.handleActivityConfigurationChanged( + new ActivityConfigChangeData(token, overrideConfig), newDisplayId); + }; } public boolean isPreHoneycomb() { @@ -3680,6 +3691,12 @@ public final class ActivityThread { if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); } + final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl(); + if (viewRoot != null) { + // TODO: Figure out the best place to set the callback. + // This looks like a place where decor view is already initialized. + viewRoot.setActivityConfigCallback(r.configCallback); + } } if (!r.onlyLocalRequest) { @@ -5028,7 +5045,7 @@ public final class ActivityThread { * @param displayId Id of the display where activity was moved to, -1 if there was no move and * value didn't change. */ - private void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) { + void handleActivityConfigurationChanged(ActivityConfigChangeData data, int displayId) { ActivityClientRecord r = mActivities.get(data.activityToken); // Check input params. if (r == null || r.activity == null) { @@ -5045,6 +5062,7 @@ public final class ActivityThread { // Perform updates. r.overrideConfig = data.overrideConfig; + final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl(); if (movedToDifferentDisplay) { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:" + r.activityInfo.name + ", displayId=" + displayId @@ -5052,13 +5070,15 @@ public final class ActivityThread { performConfigurationChangedForActivity(r, mCompatConfiguration, displayId, true /* movedToDifferentDisplay */); - final ViewRootImpl viewRoot = r.activity.mDecor.getViewRootImpl(); viewRoot.onMovedToDisplay(displayId); } else { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " + r.activityInfo.name + ", config=" + data.overrideConfig); performConfigurationChangedForActivity(r, mCompatConfiguration); } + // Notify the ViewRootImpl instance about configuration changes. It may have initiated this + // update to make sure that resources are updated before updating itself. + viewRoot.updateConfiguration(); mSomeActivitiesChanged = true; } @@ -5571,6 +5591,16 @@ public final class ActivityThread { } } + // If we use profiles, setup the dex reporter to notify package manager + // of any relevant dex loads. The idle maintenance job will use the information + // reported to optimize the loaded dex files. + // Note that we only need one global reporter per app. + // Make sure we do this before calling onCreate so that we can capture the + // complete application startup. + if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) { + BaseDexClassLoader.setReporter(DexLoadReporter.getInstance()); + } + // Install the Network Security Config Provider. This must happen before the application // code is loaded to prevent issues with instances of TLS objects being created before // the provider is installed. @@ -6284,35 +6314,26 @@ public final class ActivityThread { // add dropbox logging to libcore DropBox.setReporter(new DropBoxReporter()); - ViewRootImpl.addConfigCallback(new ComponentCallbacks2() { - @Override - public void onConfigurationChanged(Configuration newConfig) { - synchronized (mResourcesManager) { - // We need to apply this change to the resources - // immediately, because upon returning the view - // hierarchy will be informed about it. - if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) { - updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), - mResourcesManager.getConfiguration().getLocales()); - - // This actually changed the resources! Tell - // everyone about it. - if (mPendingConfiguration == null || - mPendingConfiguration.isOtherSeqNewer(newConfig)) { - mPendingConfiguration = newConfig; - - sendMessage(H.CONFIGURATION_CHANGED, newConfig); - } + ViewRootImpl.ConfigChangedCallback configChangedCallback + = (Configuration globalConfig) -> { + synchronized (mResourcesManager) { + // We need to apply this change to the resources immediately, because upon returning + // the view hierarchy will be informed about it. + if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig, + null /* compat */)) { + updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), + mResourcesManager.getConfiguration().getLocales()); + + // This actually changed the resources! Tell everyone about it. + if (mPendingConfiguration == null + || mPendingConfiguration.isOtherSeqNewer(globalConfig)) { + mPendingConfiguration = globalConfig; + sendMessage(H.CONFIGURATION_CHANGED, globalConfig); } } } - @Override - public void onLowMemory() { - } - @Override - public void onTrimMemory(int level) { - } - }); + }; + ViewRootImpl.addConfigCallback(configChangedCallback); } public static ActivityThread systemMain() { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 0f2ce3c09f00..09e7595242af 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -362,6 +362,8 @@ public class AppOpsManager { public static final String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls"; + // Warning: If an permission is added here it also has to be added to + // com.android.packageinstaller.permission.utils.EventLogger private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = { // RUNTIME PERMISSIONS // Contacts diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index 9f1a539ab240..e6452619b508 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Binder; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemProperties; @@ -430,7 +431,7 @@ public class ApplicationErrorReport implements Parcelable { dest.writeInt(throwLineNumber); dest.writeString(stackTrace); int total = dest.dataPosition()-start; - if (total > 20*1024) { + if (Binder.CHECK_PARCEL_SIZE && total > 20*1024) { Slog.d("Error", "ERR: exClass=" + exceptionClassName); Slog.d("Error", "ERR: exMsg=" + exceptionMessage); Slog.d("Error", "ERR: file=" + throwFileName); diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java new file mode 100644 index 000000000000..13f288ab7454 --- /dev/null +++ b/core/java/android/app/DexLoadReporter.java @@ -0,0 +1,168 @@ +/* + * 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.app; + +import android.os.FileUtils; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import dalvik.system.BaseDexClassLoader; +import dalvik.system.VMRuntime; + +import java.io.File; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A dex load reporter which will notify package manager of any dex file loaded + * with {@code BaseDexClassLoader}. + * The goals are: + * 1) discover secondary dex files so that they can be optimized during the + * idle maintenance job. + * 2) determine whether or not a dex file is used by an app which does not + * own it (in order to select the optimal compilation method). + * @hide + */ +/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter { + private static final String TAG = "DexLoadReporter"; + + private static final DexLoadReporter INSTANCE = new DexLoadReporter(); + + private static final boolean DEBUG = false; + + // We must guard the access to the list of data directories because + // we might have concurrent accesses. Apps might load dex files while + // new data dirs are registered (due to creation of LoadedApks via + // create createApplicationContext). + @GuardedBy("mDataDirs") + private final Set<String> mDataDirs; + + private DexLoadReporter() { + mDataDirs = new HashSet<>(); + } + + /*package*/ static DexLoadReporter getInstance() { + return INSTANCE; + } + + /** + * Register an application data directory with the reporter. + * The data directories are used to determine if a dex file is secondary dex or not. + * Note that this method may be called multiple times for the same app, registering + * different data directories. This may happen when apps share the same user id + * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user + * id, and app1 loads app2 apk, then both data directories will be registered. + */ + /*package*/ void registerAppDataDir(String packageName, String dataDir) { + if (DEBUG) { + Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir); + } + // TODO(calin): A few code paths imply that the data dir + // might be null. Investigate when that can happen. + if (dataDir != null) { + synchronized (mDataDirs) { + mDataDirs.add(dataDir); + } + } + } + + @Override + public void report(List<String> dexPaths) { + if (dexPaths.isEmpty()) { + return; + } + // Notify the package manager about the dex loads unconditionally. + // The load might be for either a primary or secondary dex file. + notifyPackageManager(dexPaths); + // Check for secondary dex files and register them for profiling if + // possible. + registerSecondaryDexForProfiling(dexPaths); + } + + private void notifyPackageManager(List<String> dexPaths) { + String packageName = ActivityThread.currentPackageName(); + try { + ActivityThread.getPackageManager().notifyDexLoad( + packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet()); + } catch (RemoteException re) { + Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re); + } + } + + private void registerSecondaryDexForProfiling(List<String> dexPaths) { + if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) { + return; + } + // Make a copy of the current data directories so that we don't keep the lock + // while registering for profiling. The registration will perform I/O to + // check for or create the profile. + String[] dataDirs; + synchronized (mDataDirs) { + dataDirs = mDataDirs.toArray(new String[0]); + } + for (String dexPath : dexPaths) { + registerSecondaryDexForProfiling(dexPath, dataDirs); + } + } + + private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) { + if (!isSecondaryDexFile(dexPath, dataDirs)) { + // The dex path is not a secondary dex file. Nothing to do. + return; + } + File secondaryProfile = getSecondaryProfileFile(dexPath); + try { + // Create the profile if not already there. + // Returns true if the file was created, false if the file already exists. + // or throws exceptions in case of errors. + boolean created = secondaryProfile.createNewFile(); + if (DEBUG && created) { + Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile); + } + } catch (IOException ex) { + Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile + + ":" + ex.getMessage()); + // Don't move forward with the registration if we failed to create the profile. + return; + } + + VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath }); + } + + // A dex file is a secondary dex file if it is in any of the registered app + // data directories. + private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) { + for (String dataDir : dataDirs) { + if (FileUtils.contains(dataDir, dexPath)) { + return true; + } + } + return false; + } + + // Secondary dex profiles are stored next to the dex file and have the same + // name with '.prof' appended. + // NOTE: Keep in sync with installd. + private File getSecondaryProfileFile(String dexPath) { + return new File(dexPath + ".prof"); + } +} diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 5ab767ba9676..5ea24804e0fd 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -66,6 +66,9 @@ interface INotificationManager ParceledListSlice getNotificationChannels(String pkg); ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted); + int getDeletedChannelCount(String pkg, int uid); + void deleteNotificationChannelGroup(String pkg, String channelGroupId); + ParceledListSlice getNotificationChannelGroups(String pkg); // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 77c4c7eea811..cf41e4e5dc9c 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -55,7 +55,6 @@ import android.view.DisplayAdjustments; import com.android.internal.util.ArrayUtils; -import dalvik.system.BaseDexClassLoader; import dalvik.system.VMRuntime; import java.io.File; @@ -752,39 +751,10 @@ public final class LoadedApk { VMRuntime.registerAppInfo(profileFile.getPath(), codePaths.toArray(new String[codePaths.size()])); - // Setup the reporter to notify package manager of any relevant dex loads. - // At this point the primary apk is loaded and will not be reported. - // Anything loaded from now on will be tracked as a potential secondary - // or foreign dex file. The goal is to enable: - // 1) monitoring and compilation of secondary dex file - // 2) track whether or not a dex file is used by other apps (used to - // determined the compilation filter of apks). - if (BaseDexClassLoader.getReporter() != DexLoadReporter.INSTANCE) { - // Set the dex load reporter if not already set. - // Note that during the app's life cycle different LoadedApks may be - // created and loaded (e.g. if two different apps share the same runtime). - BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE); - } - } - - private static class DexLoadReporter implements BaseDexClassLoader.Reporter { - private static final DexLoadReporter INSTANCE = new DexLoadReporter(); - - private DexLoadReporter() {} - - @Override - public void report(List<String> dexPaths) { - if (dexPaths.isEmpty()) { - return; - } - String packageName = ActivityThread.currentPackageName(); - try { - ActivityThread.getPackageManager().notifyDexLoad( - packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet()); - } catch (RemoteException re) { - Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re); - } - } + // Register the app data directory with the reporter. It will + // help deciding whether or not a dex file is the primary apk or a + // secondary dex. + DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir); } /** diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index a098591c8f44..aee9d38600fb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1935,7 +1935,9 @@ public class Notification implements Parcelable if (this.actions != null) { that.actions = new Action[this.actions.length]; for(int i=0; i<this.actions.length; i++) { - that.actions[i] = this.actions[i].clone(); + if ( this.actions[i] != null) { + that.actions[i] = this.actions[i].clone(); + } } } @@ -3432,7 +3434,9 @@ public class Notification implements Parcelable * @param action The action to add. */ public Builder addAction(Action action) { - mActions.add(action); + if (action != null) { + mActions.add(action); + } return this; } @@ -3446,7 +3450,9 @@ public class Notification implements Parcelable public Builder setActions(Action... actions) { mActions.clear(); for (int i = 0; i < actions.length; i++) { - mActions.add(actions[i]); + if (actions[i] != null) { + mActions.add(actions[i]); + } } return this; } @@ -5651,11 +5657,13 @@ public class Notification implements Parcelable static final String KEY_SENDER = "sender"; static final String KEY_DATA_MIME_TYPE = "type"; static final String KEY_DATA_URI= "uri"; + static final String KEY_EXTRAS_BUNDLE = "extras"; private final CharSequence mText; private final long mTimestamp; private final CharSequence mSender; + private Bundle mExtras = new Bundle(); private String mDataMimeType; private Uri mDataUri; @@ -5724,6 +5732,13 @@ public class Notification implements Parcelable } /** + * Get the extras Bundle for this message. + */ + public Bundle getExtras() { + return mExtras; + } + + /** * Get the text used to display the contact's name in the messaging experience */ public CharSequence getSender() { @@ -5760,6 +5775,9 @@ public class Notification implements Parcelable if (mDataUri != null) { bundle.putParcelable(KEY_DATA_URI, mDataUri); } + if (mExtras != null) { + bundle.putBundle(KEY_EXTRAS_BUNDLE, mExtras); + } return bundle; } @@ -5794,10 +5812,12 @@ public class Notification implements Parcelable bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER)); if (bundle.containsKey(KEY_DATA_MIME_TYPE) && bundle.containsKey(KEY_DATA_URI)) { - message.setData(bundle.getString(KEY_DATA_MIME_TYPE), (Uri) bundle.getParcelable(KEY_DATA_URI)); } + if (bundle.containsKey(KEY_EXTRAS_BUNDLE)) { + message.getExtras().putAll(bundle.getBundle(KEY_EXTRAS_BUNDLE)); + } return message; } } catch (ClassCastException e) { diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 16c85f587956..29c4520ffdcb 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.SystemApi; +import android.content.Intent; import android.media.AudioAttributes; import android.net.Uri; import android.os.Parcel; @@ -47,7 +48,6 @@ public final class NotificationChannel implements Parcelable { private static final String TAG_CHANNEL = "channel"; private static final String ATT_NAME = "name"; - private static final String ATT_NAME_RES_ID = "name_res_id"; private static final String ATT_ID = "id"; private static final String ATT_DELETED = "deleted"; private static final String ATT_PRIORITY = "priority"; @@ -141,7 +141,6 @@ public final class NotificationChannel implements Parcelable { private final String mId; private CharSequence mName; - private int mNameResId = 0; private int mImportance = DEFAULT_IMPORTANCE; private boolean mBypassDnd; private int mLockscreenVisibility = DEFAULT_VISIBILITY; @@ -162,7 +161,9 @@ public final class NotificationChannel implements Parcelable { * @param id The id of the channel. Must be unique per package. * @param name The user visible name of the channel. Unchangeable once created; use this * constructor if the channel represents a user-defined category that does not - * need to be translated. + * need to be translated. You can rename this channel when the system + * locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED} + * broadcast. * @param importance The importance of the channel. This controls how interruptive notifications * posted to this channel are. See e.g. * {@link NotificationManager#IMPORTANCE_DEFAULT}. @@ -173,21 +174,6 @@ public final class NotificationChannel implements Parcelable { this.mImportance = importance; } - /** - * Creates a notification channel. - * - * @param id The id of the channel. Must be unique per package. - * @param nameResId The resource id of the string containing the channel name. - * @param importance The importance of the channel. This controls how interruptive notifications - * posted to this channel are. See e.g. - * {@link NotificationManager#IMPORTANCE_DEFAULT}. - */ - public NotificationChannel(String id, @StringRes int nameResId, int importance) { - this.mId = id; - this.mNameResId = nameResId; - this.mImportance = importance; - } - protected NotificationChannel(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); @@ -195,7 +181,6 @@ public final class NotificationChannel implements Parcelable { mId = null; } mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mNameResId = in.readInt(); mImportance = in.readInt(); mBypassDnd = in.readByte() != 0; mLockscreenVisibility = in.readInt(); @@ -228,7 +213,6 @@ public final class NotificationChannel implements Parcelable { dest.writeByte((byte) 0); } TextUtils.writeToParcel(mName, dest, flags); - dest.writeInt(mNameResId); dest.writeInt(mImportance); dest.writeByte(mBypassDnd ? (byte) 1 : (byte) 0); dest.writeInt(mLockscreenVisibility); @@ -262,7 +246,6 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ - @SystemApi public void lockFields(int field) { mUserLockedFields |= field; } @@ -270,16 +253,15 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ - @SystemApi public void setDeleted(boolean deleted) { mDeleted = deleted; } /** - * @hide + * Sets the name of this channel. */ - public void setNameResId(@StringRes int nameResId) { - this.mNameResId = nameResId; + public void setName(CharSequence name) { + mName = name; } // Modifiable by a notification ranker. @@ -417,13 +399,6 @@ public final class NotificationChannel implements Parcelable { } /** - * Returns the resource id of the user visible name of this channel. - */ - public int getNameResId() { - return mNameResId; - } - - /** * Returns the user specified importance {e.g. @link NotificationManager#IMPORTANCE_LOW} for * notifications posted to this channel. */ @@ -556,7 +531,6 @@ public final class NotificationChannel implements Parcelable { if (getName() != null) { out.attribute(null, ATT_NAME, getName().toString()); } - out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId())); if (getImportance() != DEFAULT_IMPORTANCE) { out.attribute( null, ATT_IMPORTANCE, Integer.toString(getImportance())); @@ -614,7 +588,6 @@ public final class NotificationChannel implements Parcelable { JSONObject record = new JSONObject(); record.put(ATT_ID, getId()); record.put(ATT_NAME, getName()); - record.put(ATT_NAME_RES_ID, getNameResId()); if (getImportance() != DEFAULT_IMPORTANCE) { record.put(ATT_IMPORTANCE, NotificationListenerService.Ranking.importanceToString(getImportance())); @@ -732,7 +705,6 @@ public final class NotificationChannel implements Parcelable { NotificationChannel that = (NotificationChannel) o; - if (getNameResId() != that.getNameResId()) return false; if (getImportance() != that.getImportance()) return false; if (mBypassDnd != that.mBypassDnd) return false; if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false; @@ -762,7 +734,6 @@ public final class NotificationChannel implements Parcelable { public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; result = 31 * result + (getName() != null ? getName().hashCode() : 0); - result = 31 * result + getNameResId(); result = 31 * result + getImportance(); result = 31 * result + (mBypassDnd ? 1 : 0); result = 31 * result + getLockscreenVisibility(); @@ -784,7 +755,6 @@ public final class NotificationChannel implements Parcelable { return "NotificationChannel{" + "mId='" + mId + '\'' + ", mName=" + mName + - ", mNameResId=" + mNameResId + ", mImportance=" + mImportance + ", mBypassDnd=" + mBypassDnd + ", mLockscreenVisibility=" + mLockscreenVisibility + diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java index 288d39a706f9..2b0cd0442a0a 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.StringRes; import android.annotation.SystemApi; +import android.content.Intent; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -41,38 +42,25 @@ public final class NotificationChannelGroup implements Parcelable { private static final String TAG_GROUP = "channelGroup"; private static final String ATT_NAME = "name"; - private static final String ATT_NAME_RES_ID = "name_res_id"; private static final String ATT_ID = "id"; private final String mId; private CharSequence mName; - private int mNameResId = 0; private List<NotificationChannel> mChannels = new ArrayList<>(); /** - * Creates a notification channel. + * Creates a notification channel group. * * @param id The id of the group. Must be unique per package. - * @param name The user visible name of the group. Unchangeable once created; use this - * constructor if the group represents something user-defined that does not - * need to be translated. + * @param name The user visible name of the group. You can rename this group when the system + * locale changes by listening for the {@link Intent#ACTION_LOCALE_CHANGED} + * broadcast. */ public NotificationChannelGroup(String id, CharSequence name) { this.mId = id; this.mName = name; } - /** - * Creates a notification channel. - * - * @param id The id of the group. Must be unique per package. - * @param nameResId String resource id of the user visible name of the group. - */ - public NotificationChannelGroup(String id, @StringRes int nameResId) { - this.mId = id; - this.mNameResId = nameResId; - } - protected NotificationChannelGroup(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); @@ -80,7 +68,6 @@ public final class NotificationChannelGroup implements Parcelable { mId = null; } mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - mNameResId = in.readInt(); in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader()); } @@ -93,7 +80,6 @@ public final class NotificationChannelGroup implements Parcelable { dest.writeByte((byte) 0); } TextUtils.writeToParcel(mName, dest, flags); - dest.writeInt(mNameResId); dest.writeParcelableList(mChannels, flags); } @@ -111,19 +97,11 @@ public final class NotificationChannelGroup implements Parcelable { return mName; } - /** - * Returns the resource id of the user visible name of this group. - */ - public @StringRes int getNameResId() { - return mNameResId; - } - /* * Returns the list of channels that belong to this group * * @hide */ - @SystemApi public List<NotificationChannel> getChannels() { return mChannels; } @@ -131,7 +109,6 @@ public final class NotificationChannelGroup implements Parcelable { /** * @hide */ - @SystemApi public void addChannel(NotificationChannel channel) { mChannels.add(channel); } @@ -139,7 +116,6 @@ public final class NotificationChannelGroup implements Parcelable { /** * @hide */ - @SystemApi public void writeXml(XmlSerializer out) throws IOException { out.startTag(null, TAG_GROUP); @@ -147,9 +123,6 @@ public final class NotificationChannelGroup implements Parcelable { if (getName() != null) { out.attribute(null, ATT_NAME, getName().toString()); } - if (getNameResId() != 0) { - out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId())); - } out.endTag(null, TAG_GROUP); } @@ -162,7 +135,6 @@ public final class NotificationChannelGroup implements Parcelable { JSONObject record = new JSONObject(); record.put(ATT_ID, getId()); record.put(ATT_NAME, getName()); - record.put(ATT_NAME_RES_ID, getNameResId()); return record; } @@ -191,31 +163,22 @@ public final class NotificationChannelGroup implements Parcelable { NotificationChannelGroup that = (NotificationChannelGroup) o; - if (getNameResId() != that.getNameResId()) return false; if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { return false; } - return getChannels() != null ? getChannels().equals(that.getChannels()) - : that.getChannels() == null; - + return true; } @Override public NotificationChannelGroup clone() { - if (getName() != null) { - return new NotificationChannelGroup(getId(), getName()); - } else { - return new NotificationChannelGroup(getId(), getNameResId()); - } + return new NotificationChannelGroup(getId(), getName()); } @Override public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; result = 31 * result + (getName() != null ? getName().hashCode() : 0); - result = 31 * result + getNameResId(); - result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0); return result; } @@ -224,7 +187,6 @@ public final class NotificationChannelGroup implements Parcelable { return "NotificationChannelGroup{" + "mId='" + mId + '\'' + ", mName=" + mName + - ", mNameResId=" + mNameResId + ", mChannels=" + mChannels + '}'; } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 2296838eddb3..0379970762ab 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -385,7 +385,7 @@ public class NotificationManager /** * Creates a group container for {@link NotificationChannel} objects. * - * This is a no-op for groups that already exist. + * This can be used to rename an existing group. * <p> * Group information is only used for presentation, not for behavior. Groups are optional * for channels, and you can have a mix of channels that belong to groups and channels @@ -421,21 +421,22 @@ public class NotificationManager /** * Creates a notification channel that notifications can be posted to. * - * This is a no-op for channels that already exist. + * This can also be used to restore a deleted channel and to rename an existing 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 * value. If the provided channel is malformed, a RemoteException will be - * thrown. If the channel already exists, it will not be modified. + * thrown. */ public void createNotificationChannel(@NonNull NotificationChannel channel) { createNotificationChannels(Arrays.asList(channel)); } /** - * Creates multiple notification channels that different notifications can be posted to. + * Creates multiple notification channels that different notifications can be posted to. See + * {@link #createNotificationChannel(NotificationChannel)}. * - * @param channels the list of channels to attempt to create. If any of these channels already - * exist, they will not be modified. + * @param channels the list of channels to attempt to create. */ public void createNotificationChannels(@NonNull List<NotificationChannel> channels) { INotificationManager service = getService(); @@ -497,6 +498,30 @@ public class NotificationManager } /** + * Returns all notification channel groups belonging to the calling app. + */ + public List<NotificationChannelGroup> getNotificationChannelGroups() { + INotificationManager service = getService(); + try { + return service.getNotificationChannelGroups(mContext.getPackageName()).getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Deletes the given notification channel group. + */ + public void deleteNotificationChannelGroup(String groupId) { + INotificationManager service = getService(); + try { + service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @hide */ @TestApi diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java index 5958bc14d474..e7fe407b29b3 100644 --- a/core/java/android/app/RemoteAction.java +++ b/core/java/android/app/RemoteAction.java @@ -41,12 +41,14 @@ public final class RemoteAction implements Parcelable { private final CharSequence mTitle; private final CharSequence mContentDescription; private final PendingIntent mActionIntent; + private boolean mEnabled; RemoteAction(Parcel in) { mIcon = Icon.CREATOR.createFromParcel(in); mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mActionIntent = PendingIntent.CREATOR.createFromParcel(in); + mEnabled = in.readBoolean(); } public RemoteAction(@NonNull Icon icon, @NonNull CharSequence title, @@ -59,6 +61,21 @@ public final class RemoteAction implements Parcelable { mTitle = title; mContentDescription = contentDescription; mActionIntent = intent; + mEnabled = true; + } + + /** + * Sets whether this action is enabled. + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + /** + * Return whether this action is enabled. + */ + public boolean isEnabled() { + return mEnabled; } /** @@ -91,7 +108,9 @@ public final class RemoteAction implements Parcelable { @Override public RemoteAction clone() { - return new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent); + RemoteAction action = new RemoteAction(mIcon, mTitle, mContentDescription, mActionIntent); + action.setEnabled(mEnabled); + return action; } @Override @@ -105,11 +124,13 @@ public final class RemoteAction implements Parcelable { TextUtils.writeToParcel(mTitle, out, flags); TextUtils.writeToParcel(mContentDescription, out, flags); mActionIntent.writeToParcel(out, flags); + out.writeBoolean(mEnabled); } public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("title=" + mTitle); + pw.print(" enabled=" + mEnabled); pw.print(" contentDescription=" + mContentDescription); pw.print(" icon=" + mIcon); pw.print(" action=" + mActionIntent.getIntent()); diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 0fb59668a201..d9b6eed4fc4d 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -17,6 +17,7 @@ package android.app.admin; import android.accounts.AccountManager; +import android.annotation.BroadcastBehavior; import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -81,6 +82,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * that other applications can not abuse it. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"; @@ -94,6 +96,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * to the user before they disable your admin. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"; @@ -115,6 +118,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * its intent filter. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"; @@ -131,6 +135,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED"; @@ -147,6 +152,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED"; @@ -160,6 +166,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED"; @@ -173,6 +180,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING"; @@ -187,6 +195,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @see DevicePolicyManager#isLockTaskPermitted(String) */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING"; @@ -200,6 +209,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @see DevicePolicyManager#isLockTaskPermitted(String) */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING"; @@ -232,6 +242,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * <p>Output: Nothing</p> */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE"; @@ -244,6 +255,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_BUGREPORT_SHARING_DECLINED = "android.app.action.BUGREPORT_SHARING_DECLINED"; @@ -256,6 +268,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_BUGREPORT_FAILED = "android.app.action.BUGREPORT_FAILED"; /** @@ -266,6 +279,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_BUGREPORT_SHARE = "android.app.action.BUGREPORT_SHARE"; @@ -274,6 +288,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_SECURITY_LOGS_AVAILABLE = "android.app.action.SECURITY_LOGS_AVAILABLE"; @@ -283,6 +298,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_NETWORK_LOGS_AVAILABLE = "android.app.action.NETWORK_LOGS_AVAILABLE"; @@ -314,7 +330,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_USER_ADDED = "android.app.action.USER_ADDED"; + @BroadcastBehavior(explicitOnly = true) + public static final String ACTION_USER_ADDED = "android.app.action.USER_ADDED"; /** * Broadcast action: notify the device owner that a user or profile has been removed. @@ -323,6 +340,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_USER_REMOVED = "android.app.action.USER_REMOVED"; /** @@ -401,6 +419,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_NOTIFY_PENDING_SYSTEM_UPDATE = "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE"; diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index b1fbc8f18818..27bfb512f9dc 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -1612,9 +1612,8 @@ public class AssistStructure implements Parcelable { return newChild(index, false, 0, 0); } - // TODO(b/33197203, b/33802548): add CTS/unit test @Override - public ViewStructure newChildForAutofill(int index, int virtualId, int flags) { + public ViewStructure newChild(int index, int virtualId, int flags) { return newChild(index, true, virtualId, flags); } @@ -1624,7 +1623,7 @@ public class AssistStructure implements Parcelable { } @Override - public ViewStructure asyncNewChildForAutofill(int index, int virtualId, int flags) { + public ViewStructure asyncNewChild(int index, int virtualId, int flags) { return asyncNewChild(index, true, virtualId); } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 67c791df3c9a..74a39e85e029 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -16,8 +16,11 @@ package android.appwidget; +import android.annotation.BroadcastBehavior; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -81,12 +84,14 @@ public class AppWidgetManager { * * @see #ACTION_APPWIDGET_CONFIGURE */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK"; /** * Similar to ACTION_APPWIDGET_PICK, but used from keyguard * @hide */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK"; @@ -133,6 +138,7 @@ public class AppWidgetManager { * @see #ACTION_APPWIDGET_CONFIGURE * */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND"; /** @@ -157,6 +163,7 @@ public class AppWidgetManager { * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} * broadcast. */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE"; /** @@ -290,6 +297,8 @@ public class AppWidgetManager { * * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; /** @@ -302,6 +311,8 @@ public class AppWidgetManager { * AppWidgetProvider.onAppWidgetOptionsChanged(Context context, * AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS"; /** @@ -312,6 +323,8 @@ public class AppWidgetManager { * * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED"; /** @@ -322,6 +335,8 @@ public class AppWidgetManager { * * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED"; /** @@ -334,6 +349,8 @@ public class AppWidgetManager { * * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context) */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED"; /** @@ -365,6 +382,8 @@ public class AppWidgetManager { * * @see #ACTION_APPWIDGET_HOST_RESTORED */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED"; @@ -402,6 +421,8 @@ public class AppWidgetManager { * * @see #ACTION_APPWIDGET_RESTORED */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED"; diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 488511b49b88..4e1e42da4fe7 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1483,6 +1483,25 @@ public final class BluetoothAdapter { } /** + * Return the maximum LE advertising data length, + * if LE Extended Advertising feature is supported. + * + * @return the maximum LE advertising data length. + */ + public int getLeMaximumAdvertisingDataLength() { + if (!getLeAccess()) return 0; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getLeMaximumAdvertisingDataLength(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return 0; + } + + /** * Return true if hardware has entries available for matching beacons * * @return true if there are hw entries available for matching beacons diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index 76ca554e5984..b33781729b62 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -108,6 +108,7 @@ interface IBluetooth boolean isLeCodedPhySupported(); boolean isLeExtendedAdvertisingSupported(); boolean isLePeriodicAdvertisingSupported(); + int getLeMaximumAdvertisingDataLength(); BluetoothActivityEnergyInfo reportActivityInfo(); /** diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 33fedc718980..29f29e7dba4e 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -50,14 +50,6 @@ interface IBluetoothGatt { void stopScan(in int scannerId); void flushPendingBatchResults(in int scannerId); - void registerAdvertiser(in IAdvertiserCallback callback); - void unregisterAdvertiser(in int advertiserId); - void startMultiAdvertising(in int advertiserId, - in AdvertiseData advertiseData, - in AdvertiseData scanResponse, - in AdvertiseSettings settings); - void stopMultiAdvertising(in int advertiserId); - void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData, in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters, in AdvertiseData periodicData, in IAdvertisingSetCallback callback); diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index e03c9477a6a3..c9f1d7a32efb 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -28,6 +28,7 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -60,11 +61,12 @@ public final class BluetoothLeAdvertiser { private final IBluetoothManager mBluetoothManager; private final Handler mHandler; private BluetoothAdapter mBluetoothAdapter; - private final Map<AdvertiseCallback, AdvertiseCallbackWrapper> - mLeAdvertisers = new HashMap<AdvertiseCallback, AdvertiseCallbackWrapper>(); + private final Map<AdvertiseCallback, AdvertisingSetCallback> + mLegacyAdvertisers = new HashMap<>(); private final Map<AdvertisingSetCallback, IAdvertisingSetCallback> - advertisingSetCallbackWrappers = new HashMap<>(); - private final Map<Integer, AdvertisingSet> advertisingSets = new HashMap<>(); + mCallbackWrappers = Collections.synchronizedMap(new HashMap<>()); + private final Map<Integer, AdvertisingSet> + mAdvertisingSets = Collections.synchronizedMap(new HashMap<>()); /** * Use BluetoothAdapter.getLeAdvertiser() instead. @@ -109,7 +111,7 @@ public final class BluetoothLeAdvertiser { public void startAdvertising(AdvertiseSettings settings, AdvertiseData advertiseData, AdvertiseData scanResponse, final AdvertiseCallback callback) { - synchronized (mLeAdvertisers) { + synchronized (mLegacyAdvertisers) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); @@ -120,25 +122,65 @@ public final class BluetoothLeAdvertiser { postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE); return; } - if (mLeAdvertisers.containsKey(callback)) { + if (mLegacyAdvertisers.containsKey(callback)) { postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED); return; } - IBluetoothGatt gatt; - try { - gatt = mBluetoothManager.getBluetoothGatt(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); - return; + AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder(); + parameters.setLegacyMode(true); + parameters.setConnectable(isConnectable); + parameters.setTimeout(settings.getTimeout()); + if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) { + parameters.setInterval(1600); // 1s + } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) { + parameters.setInterval(400); // 250ms + } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) { + parameters.setInterval(160); // 100ms + } + + if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) { + parameters.setTxPowerLevel(-21); + } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) { + parameters.setTxPowerLevel(-15); + } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) { + parameters.setTxPowerLevel(-7); + } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) { + parameters.setTxPowerLevel(1); } - AdvertiseCallbackWrapper wrapper = new AdvertiseCallbackWrapper(callback, advertiseData, - scanResponse, settings, gatt); - wrapper.startRegisteration(); + + AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings); + mLegacyAdvertisers.put(callback, wrapped); + startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null, + wrapped); } } + AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) { + return new AdvertisingSetCallback() { + public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int status) { + if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { + postStartFailure(callback, status); + return; + } + + postStartSuccess(callback, settings); + } + + /* Legacy advertiser is disabled on timeout */ + public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) { + if (enabled == true) { + Log.e(TAG, "Legacy advertiser should be only disabled on timeout," + + " but was enabled!"); + return; + } + + stopAdvertising(callback); + } + + }; + } + /** * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in * {@link BluetoothLeAdvertiser#startAdvertising}. @@ -148,20 +190,21 @@ public final class BluetoothLeAdvertiser { * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop. */ public void stopAdvertising(final AdvertiseCallback callback) { - synchronized (mLeAdvertisers) { + synchronized (mLegacyAdvertisers) { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } - AdvertiseCallbackWrapper wrapper = mLeAdvertisers.get(callback); + AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback); if (wrapper == null) return; - wrapper.stopAdvertising(); + + stopAdvertisingSet(wrapper); } } /** * Creates a new advertising set. If operation succeed, device will start advertising. This * method returns immediately, the operation status is delivered through - * {@code callback.onNewAdvertisingSet()}. + * {@code callback.onAdvertisingSetStarted()}. * <p> * @param parameters advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. @@ -180,7 +223,7 @@ public final class BluetoothLeAdvertiser { /** * Creates a new advertising set. If operation succeed, device will start advertising. This * method returns immediately, the operation status is delivered through - * {@code callback.onNewAdvertisingSet()}. + * {@code callback.onAdvertisingSetStarted()}. * <p> * @param parameters advertising set parameters. * @param advertiseData Advertisement data to be broadcasted. @@ -209,7 +252,10 @@ public final class BluetoothLeAdvertiser { } IAdvertisingSetCallback wrapped = wrap(callback, handler); - advertisingSetCallbackWrappers.put(callback, wrapped); + if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) { + throw new IllegalArgumentException( + "callback instance already associated with advertising"); + } try { gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, @@ -229,10 +275,9 @@ public final class BluetoothLeAdvertiser { throw new IllegalArgumentException("callback cannot be null"); } - IAdvertisingSetCallback wrapped = advertisingSetCallbackWrappers.remove(callback); + IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback); if (wrapped == null) { - throw new IllegalArgumentException( - "callback does not represent valid registered callback."); + return; } IBluetoothGatt gatt; @@ -251,7 +296,9 @@ public final class BluetoothLeAdvertiser { * @hide */ public void cleanup() { - mLeAdvertisers.clear(); + mLegacyAdvertisers.clear(); + mCallbackWrappers.clear(); + mAdvertisingSets.clear(); } // Compute the size of advertisement data or scan resp @@ -317,13 +364,13 @@ public final class BluetoothLeAdvertiser { public void run() { if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) { callback.onAdvertisingSetStarted(null, status); - advertisingSetCallbackWrappers.remove(callback); + mCallbackWrappers.remove(callback); return; } AdvertisingSet advertisingSet = new AdvertisingSet(advertiserId, mBluetoothManager); - advertisingSets.put(advertiserId, advertisingSet); + mAdvertisingSets.put(advertiserId, advertisingSet); callback.onAdvertisingSetStarted(advertisingSet, status); } }); @@ -333,10 +380,10 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onAdvertisingSetStopped(advertisingSet); - advertisingSets.remove(advertiserId); - advertisingSetCallbackWrappers.remove(callback); + mAdvertisingSets.remove(advertiserId); + mCallbackWrappers.remove(callback); } }); } @@ -345,7 +392,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onAdvertisingEnabled(advertisingSet, enabled, status); } }); @@ -355,7 +402,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onAdvertisingDataSet(advertisingSet, status); } }); @@ -365,7 +412,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onScanResponseDataSet(advertisingSet, status); } }); @@ -375,7 +422,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onAdvertisingParametersUpdated(advertisingSet, status); } }); @@ -385,7 +432,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status); } }); @@ -395,7 +442,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onPeriodicAdvertisingDataSet(advertisingSet, status); } }); @@ -405,7 +452,7 @@ public final class BluetoothLeAdvertiser { handler.post(new Runnable() { @Override public void run() { - AdvertisingSet advertisingSet = advertisingSets.get(advertiserId); + AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); callback.onPeriodicAdvertisingEnable(advertisingSet, enable, status); } }); @@ -413,144 +460,6 @@ public final class BluetoothLeAdvertiser { }; } - /** - * Bluetooth GATT interface callbacks for advertising. - */ - private class AdvertiseCallbackWrapper extends IAdvertiserCallback.Stub { - private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000; - private final AdvertiseCallback mAdvertiseCallback; - private final AdvertiseData mAdvertisement; - private final AdvertiseData mScanResponse; - private final AdvertiseSettings mSettings; - private final IBluetoothGatt mBluetoothGatt; - - // mAdvertiserId -1: not registered - // -2: advertise stopped or registration timeout - // >=0: registered and advertising started - private int mAdvertiserId; - private boolean mIsAdvertising = false; - private int registrationError = AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR; - - public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback, - AdvertiseData advertiseData, AdvertiseData scanResponse, - AdvertiseSettings settings, - IBluetoothGatt bluetoothGatt) { - mAdvertiseCallback = advertiseCallback; - mAdvertisement = advertiseData; - mScanResponse = scanResponse; - mSettings = settings; - mBluetoothGatt = bluetoothGatt; - mAdvertiserId = -1; - } - - public void startRegisteration() { - synchronized (this) { - if (mAdvertiserId == -2) return; - - try { - mBluetoothGatt.registerAdvertiser(this); - wait(LE_CALLBACK_TIMEOUT_MILLIS); - } catch (InterruptedException | RemoteException e) { - Log.e(TAG, "Failed to start registeration", e); - } - if (mAdvertiserId >= 0 && mIsAdvertising) { - mLeAdvertisers.put(mAdvertiseCallback, this); - } else if (mAdvertiserId < 0) { - - // Registration timeout, reset mClientIf to -2 so no subsequent operations can - // proceed. - if (mAdvertiserId == -1) mAdvertiserId = -2; - // Post internal error if registration failed. - postStartFailure(mAdvertiseCallback, registrationError); - } else { - // Unregister application if it's already registered but advertise failed. - try { - mBluetoothGatt.unregisterAdvertiser(mAdvertiserId); - mAdvertiserId = -2; - } catch (RemoteException e) { - Log.e(TAG, "remote exception when unregistering", e); - } - } - } - } - - public void stopAdvertising() { - synchronized (this) { - try { - mBluetoothGatt.stopMultiAdvertising(mAdvertiserId); - wait(LE_CALLBACK_TIMEOUT_MILLIS); - } catch (InterruptedException | RemoteException e) { - Log.e(TAG, "Failed to stop advertising", e); - } - // Advertise callback should have been removed from LeAdvertisers when - // onMultiAdvertiseCallback was called. In case onMultiAdvertiseCallback is never - // invoked and wait timeout expires, remove callback here. - if (mLeAdvertisers.containsKey(mAdvertiseCallback)) { - mLeAdvertisers.remove(mAdvertiseCallback); - } - } - } - - /** - * Advertiser interface registered - app is ready to go - */ - @Override - public void onAdvertiserRegistered(int status, int advertiserId) { - Log.d(TAG, "onAdvertiserRegistered() - status=" + status + " advertiserId=" + advertiserId); - synchronized (this) { - if (status == BluetoothGatt.GATT_SUCCESS) { - try { - if (mAdvertiserId == -2) { - // Registration succeeds after timeout, unregister advertiser. - mBluetoothGatt.unregisterAdvertiser(advertiserId); - } else { - mAdvertiserId = advertiserId; - mBluetoothGatt.startMultiAdvertising(mAdvertiserId, mAdvertisement, - mScanResponse, mSettings); - } - return; - } catch (RemoteException e) { - Log.e(TAG, "failed to start advertising", e); - } - } else if (status == AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) { - registrationError = status; - } - // Registration failed. - mAdvertiserId = -2; - notifyAll(); - } - } - - @Override - public void onMultiAdvertiseCallback(int status, boolean isStart, - AdvertiseSettings settings) { - synchronized (this) { - if (isStart) { - if (status == AdvertiseCallback.ADVERTISE_SUCCESS) { - // Start success - mIsAdvertising = true; - postStartSuccess(mAdvertiseCallback, settings); - } else { - // Start failure. - postStartFailure(mAdvertiseCallback, status); - } - } else { - // unregister advertiser for stop. - try { - mBluetoothGatt.unregisterAdvertiser(mAdvertiserId); - mAdvertiserId = -2; - mIsAdvertising = false; - mLeAdvertisers.remove(mAdvertiseCallback); - } catch (RemoteException e) { - Log.e(TAG, "remote exception when unregistering", e); - } - } - notifyAll(); - } - - } - } - private void postStartFailure(final AdvertiseCallback callback, final int error) { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1f01e28ea0b0..4dc6fd227243 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -17,6 +17,7 @@ package android.content; import android.annotation.AnyRes; +import android.annotation.BroadcastBehavior; import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -1992,6 +1993,7 @@ public class Intent implements Parcelable, Cloneable { * This is a protected intent that can only be sent by the system. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @BroadcastBehavior(includeBackground = true) public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 33f57e025473..10ffab2d813d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2355,6 +2355,13 @@ public abstract class PackageManager { = "android.hardware.vr.high_performance"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device implements headtracking suitable for a VR device. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking"; + + /** * Action to external storage service to clean out removed apps. * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index e15a0e240711..be6dc05ace5f 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -211,6 +211,14 @@ public class PackageParser { CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); } + private static final boolean LOG_UNSAFE_BROADCASTS = false; + + // Set of broadcast actions that are safe for manifest receivers + private static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); + static { + SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); + } + /** @hide */ public static class NewPermissionInfo { public final String name; @@ -4203,6 +4211,7 @@ public class PackageParser { sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false); if (visibleToEphemeral) { a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL; + owner.visibleToInstantApps = true; } sa.recycle(); @@ -4247,6 +4256,18 @@ public class PackageParser { if (intent.isVisibleToInstantApp()) { a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL; } + if (LOG_UNSAFE_BROADCASTS && receiver + && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) { + for (int i = 0; i < intent.countActions(); i++) { + final String action = intent.getAction(i); + if (action == null || !action.startsWith("android.")) continue; + if (!SAFE_BROADCASTS.contains(action)) { + Slog.w(TAG, "Broadcast " + action + " may never be delivered to " + + owner.packageName + " as requested at: " + + parser.getPositionDescription()); + } + } + } } else if (!receiver && parser.getName().equals("preferred")) { ActivityIntentInfo intent = new ActivityIntentInfo(a); if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/, @@ -4696,6 +4717,7 @@ public class PackageParser { sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); if (visibleToEphemeral) { p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL; + owner.visibleToInstantApps = true; } sa.recycle(); @@ -5012,6 +5034,7 @@ public class PackageParser { sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false); if (visibleToEphemeral) { s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL; + owner.visibleToInstantApps = true; } sa.recycle(); @@ -5615,6 +5638,11 @@ public class PackageParser { public byte[] restrictUpdateHash; + /** + * Set if the app or any of its components are visible to Instant Apps. + */ + public boolean visibleToInstantApps; + public Package(String packageName) { this.packageName = packageName; this.manifestPackageName = packageName; diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 8bc65af65ef1..e3b97e82f6c8 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -100,6 +100,8 @@ public class CameraDeviceImpl extends CameraDevice private final CameraCharacteristics mCharacteristics; private final int mTotalPartialCount; + private static final long NANO_PER_SECOND = 1000000000; //ns + /** * A list tracking request and its expected last regular frame number and last reprocess frame * number. Updated when calling ICameraDeviceUser methods. @@ -1239,6 +1241,14 @@ public class CameraDeviceImpl extends CameraDevice private final List<CaptureRequest> mRequestList; private final Handler mHandler; private final int mSessionId; + /** + * <p>Determine if the callback holder is for a constrained high speed request list that + * expects batched capture results. Capture results will be batched if the request list + * is interleaved with preview and video requests. Capture results won't be batched if the + * request list only contains preview requests, or if the request doesn't belong to a + * constrained high speed list. + */ + private final boolean mHasBatchedOutputs; CaptureCallbackHolder(CaptureCallback callback, List<CaptureRequest> requestList, Handler handler, boolean repeating, int sessionId) { @@ -1251,6 +1261,25 @@ public class CameraDeviceImpl extends CameraDevice mRequestList = new ArrayList<CaptureRequest>(requestList); mCallback = callback; mSessionId = sessionId; + + // Check whether this callback holder is for batched outputs. + // The logic here should match createHighSpeedRequestList. + boolean hasBatchedOutputs = true; + for (int i = 0; i < requestList.size(); i++) { + CaptureRequest request = requestList.get(i); + if (!request.isPartOfCRequestList()) { + hasBatchedOutputs = false; + break; + } + if (i == 0) { + Collection<Surface> targets = request.getTargets(); + if (targets.size() != 2) { + hasBatchedOutputs = false; + break; + } + } + } + mHasBatchedOutputs = hasBatchedOutputs; } public boolean isRepeating() { @@ -1288,6 +1317,14 @@ public class CameraDeviceImpl extends CameraDevice public int getSessionId() { return mSessionId; } + + public int getRequestCount() { + return mRequestList.size(); + } + + public boolean hasBatchedOutputs() { + return mHasBatchedOutputs; + } } /** @@ -1777,10 +1814,27 @@ public class CameraDeviceImpl extends CameraDevice @Override public void run() { if (!CameraDeviceImpl.this.isClosed()) { - holder.getCallback().onCaptureStarted( - CameraDeviceImpl.this, - holder.getRequest(resultExtras.getSubsequenceId()), - timestamp, frameNumber); + final int subsequenceId = resultExtras.getSubsequenceId(); + final CaptureRequest request = holder.getRequest(subsequenceId); + + if (holder.hasBatchedOutputs()) { + // Send derived onCaptureStarted for requests within the batch + final Range<Integer> fpsRange = + request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); + for (int i = 0; i < holder.getRequestCount(); i++) { + holder.getCallback().onCaptureStarted( + CameraDeviceImpl.this, + holder.getRequest(i), + timestamp - (subsequenceId - i) * + NANO_PER_SECOND/fpsRange.getUpper(), + frameNumber - (subsequenceId - i)); + } + } else { + holder.getCallback().onCaptureStarted( + CameraDeviceImpl.this, + holder.getRequest(resultExtras.getSubsequenceId()), + timestamp, frameNumber); + } } } }); @@ -1845,46 +1899,91 @@ public class CameraDeviceImpl extends CameraDevice Runnable resultDispatch = null; CaptureResult finalResult; + // Make a copy of the native metadata before it gets moved to a CaptureResult + // object. + final CameraMetadataNative resultCopy; + if (holder.hasBatchedOutputs()) { + resultCopy = new CameraMetadataNative(result); + } else { + resultCopy = null; + } // Either send a partial result or the final capture completed result if (isPartialResult) { final CaptureResult resultAsCapture = new CaptureResult(result, request, resultExtras); - // Partial result resultDispatch = new Runnable() { @Override public void run() { - if (!CameraDeviceImpl.this.isClosed()){ - holder.getCallback().onCaptureProgressed( - CameraDeviceImpl.this, - request, - resultAsCapture); + if (!CameraDeviceImpl.this.isClosed()) { + if (holder.hasBatchedOutputs()) { + // Send derived onCaptureProgressed for requests within + // the batch. + for (int i = 0; i < holder.getRequestCount(); i++) { + CameraMetadataNative resultLocal = + new CameraMetadataNative(resultCopy); + CaptureResult resultInBatch = new CaptureResult( + resultLocal, holder.getRequest(i), resultExtras); + + holder.getCallback().onCaptureProgressed( + CameraDeviceImpl.this, + holder.getRequest(i), + resultInBatch); + } + } else { + holder.getCallback().onCaptureProgressed( + CameraDeviceImpl.this, + request, + resultAsCapture); + } } } }; - finalResult = resultAsCapture; } else { List<CaptureResult> partialResults = mFrameNumberTracker.popPartialResults(frameNumber); + final long sensorTimestamp = + result.get(CaptureResult.SENSOR_TIMESTAMP); + final Range<Integer> fpsRange = + request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); + final int subsequenceId = resultExtras.getSubsequenceId(); final TotalCaptureResult resultAsCapture = new TotalCaptureResult(result, request, resultExtras, partialResults, holder.getSessionId()); - // Final capture result resultDispatch = new Runnable() { @Override public void run() { if (!CameraDeviceImpl.this.isClosed()){ - holder.getCallback().onCaptureCompleted( - CameraDeviceImpl.this, - request, - resultAsCapture); + if (holder.hasBatchedOutputs()) { + // Send derived onCaptureCompleted for requests within + // the batch. + for (int i = 0; i < holder.getRequestCount(); i++) { + resultCopy.set(CaptureResult.SENSOR_TIMESTAMP, + sensorTimestamp - (subsequenceId - i) * + NANO_PER_SECOND/fpsRange.getUpper()); + CameraMetadataNative resultLocal = + new CameraMetadataNative(resultCopy); + TotalCaptureResult resultInBatch = new TotalCaptureResult( + resultLocal, holder.getRequest(i), resultExtras, + partialResults, holder.getSessionId()); + + holder.getCallback().onCaptureCompleted( + CameraDeviceImpl.this, + holder.getRequest(i), + resultInBatch); + } + } else { + holder.getCallback().onCaptureCompleted( + CameraDeviceImpl.this, + request, + resultAsCapture); + } } } }; - finalResult = resultAsCapture; } diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java index fc7d0d2afbd4..89648931fd53 100644 --- a/core/java/android/hardware/radio/RadioModule.java +++ b/core/java/android/hardware/radio/RadioModule.java @@ -16,6 +16,8 @@ package android.hardware.radio; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; @@ -23,6 +25,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import java.lang.ref.WeakReference; +import java.util.List; import java.util.UUID; /** @@ -76,6 +79,8 @@ public class RadioModule extends RadioTuner { public native int getProgramInformation(RadioManager.ProgramInfo[] info); + public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter); + public native boolean isAntennaConnected(); public native boolean hasControl(); diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java index 5c82555663de..c8034eb94992 100644 --- a/core/java/android/hardware/radio/RadioTuner.java +++ b/core/java/android/hardware/radio/RadioTuner.java @@ -16,6 +16,8 @@ package android.hardware.radio; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; @@ -23,6 +25,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import java.lang.ref.WeakReference; +import java.util.List; import java.util.UUID; /** @@ -209,6 +212,20 @@ public abstract class RadioTuner { public abstract int getProgramInformation(RadioManager.ProgramInfo[] info); /** + * Get the list of discovered radio stations. + * + * To get the full list, set filter to null or empty string. Otherwise, client application + * must verify vendor product/name before setting this parameter to anything else. + * + * @param filter vendor-specific selector for radio stations. + * @return a list of radio stations. + * @throws IllegalStateException if the scan is in progress or has not been started. + * @throws IllegalArgumentException if the filter argument is not valid. + * @hide FutureFeature + */ + public abstract @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter); + + /** * Get current antenna connection state for current configuration. * Only valid if a configuration has been applied. * @return {@code true} if the antenna is connected, {@code false} otherwise. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 01369791fd38..7906707c0133 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -66,7 +66,8 @@ public class Binder implements IBinder { * of classes can potentially create leaks. */ private static final boolean FIND_POTENTIAL_LEAKS = false; - private static final boolean CHECK_PARCEL_SIZE = false; + /** @hide */ + public static final boolean CHECK_PARCEL_SIZE = false; static final String TAG = "Binder"; /** @hide */ diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index a265dd08a92f..94fd5b074b82 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -219,6 +219,7 @@ public class HwParcel { public native final void writeStatus(int status); public native final void verifySuccess(); public native final void releaseTemporaryStorage(); + public native final void release(); public native final void send(); diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index caea2020244c..f503b3a2d33f 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -2638,7 +2638,7 @@ public final class StrictMode { dest.writeString(broadcastIntentAction); dest.writeStringArray(tags); int total = dest.dataPosition()-start; - if (total > 10*1024) { + if (Binder.CHECK_PARCEL_SIZE && total > 10*1024) { Slog.d(TAG, "VIO: policy=" + policy + " dur=" + durationMillis + " numLoop=" + violationNumThisLoop + " anim=" + numAnimationsRunning diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a638cd43aba9..f6712f840585 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; @@ -763,6 +764,16 @@ public class UserManager { public static final int PIN_VERIFICATION_SUCCESS = -1; /** + * Sent when user restrictions have changed. + * + * @hide + */ + @SystemApi + @TestApi // To allow seeing it from CTS. + public static final String ACTION_USER_RESTRICTIONS_CHANGED = + "android.os.action.USER_RESTRICTIONS_CHANGED"; + + /** * Error result indicating that this user is not allowed to add other users on this device. * This is a result code returned from the activity created by the intent * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}. diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 6663f03a6383..6213d27bfc70 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -215,8 +215,10 @@ public final class SaveInfo implements Parcelable { * @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty. */ public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) { + if (false) {// TODO(b/33197203): re-move when clients use it Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0, - "must have at least on required id: " + Arrays.toString(requiredIds)); + "must have at least one required id: " + Arrays.toString(requiredIds)); + } switch (type) { case SAVE_DATA_TYPE_PASSWORD: case SAVE_DATA_TYPE_ADDRESS: diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 70e0461ce73f..f55c7cfb4ba5 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -149,13 +149,13 @@ public abstract class NotificationListenerService extends Service { // Notification cancellation reasons /** Notification was canceled by the status bar reporting a notification click. */ - public static final int REASON_DELEGATE_CLICK = 1; + public static final int REASON_CLICK = 1; /** Notification was canceled by the status bar reporting a user dismissal. */ - public static final int REASON_DELEGATE_CANCEL = 2; + public static final int REASON_CANCEL = 2; /** Notification was canceled by the status bar reporting a user dismiss all. */ - public static final int REASON_DELEGATE_CANCEL_ALL = 3; + public static final int REASON_CANCEL_ALL = 3; /** Notification was canceled by the status bar reporting an inflation error. */ - public static final int REASON_DELEGATE_ERROR = 4; + public static final int REASON_ERROR = 4; /** Notification was canceled by the package manager modifying the package. */ public static final int REASON_PACKAGE_CHANGED = 5; /** Notification was canceled by the owning user context being stopped. */ diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl index 10e417784700..6034c1820972 100644 --- a/core/java/android/service/vr/IVrManager.aidl +++ b/core/java/android/service/vr/IVrManager.aidl @@ -50,5 +50,13 @@ interface IVrManager { * @param enabled true if the device should be placed in persistent VR mode. */ void setPersistentVrModeEnabled(in boolean enabled); + + /** + * Return current virtual display id. + * + * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display + * currently, else return the display id of the virtual display + */ + int getCompatibilityDisplayId(); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 483a49ba1697..6bbb0ff9861b 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -18,11 +18,11 @@ package android.service.wallpaper; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.util.MergedConfiguration; import android.view.WindowInsets; import com.android.internal.R; import com.android.internal.os.HandlerCaller; -import com.android.internal.util.ScreenShapeHelper; import com.android.internal.view.BaseIWindow; import com.android.internal.view.BaseSurfaceHolder; @@ -32,7 +32,6 @@ import android.app.Service; import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.display.DisplayManager; @@ -55,7 +54,6 @@ import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; import java.io.FileDescriptor; @@ -169,7 +167,7 @@ public abstract class WallpaperService extends Service { final Rect mFinalSystemInsets = new Rect(); final Rect mFinalStableInsets = new Rect(); final Rect mBackdropFrame = new Rect(); - final Configuration mConfiguration = new Configuration(); + final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); final WindowManager.LayoutParams mLayout = new WindowManager.LayoutParams(); @@ -288,7 +286,7 @@ public abstract class WallpaperService extends Service { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, - Configuration newConfig, Rect backDropRect, boolean forceLayout, + MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED, reportDraw ? 1 : 0, outsets); @@ -568,7 +566,8 @@ public abstract class WallpaperService extends Service { out.print(mVisibleInsets.toShortString()); out.print(" mWinFrame="); out.print(mWinFrame.toShortString()); out.print(" mContentInsets="); out.println(mContentInsets.toShortString()); - out.print(prefix); out.print("mConfiguration="); out.println(mConfiguration); + out.print(prefix); out.print("mConfiguration="); + out.println(mMergedConfiguration.getMergedConfiguration()); out.print(prefix); out.print("mLayout="); out.println(mLayout); synchronized (mLock) { out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset); @@ -695,7 +694,7 @@ public abstract class WallpaperService extends Service { mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame, - mConfiguration, mSurfaceHolder.mSurface); + mMergedConfiguration, mSurfaceHolder.mSurface); if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java new file mode 100644 index 000000000000..e5aa2b5b4ce7 --- /dev/null +++ b/core/java/android/util/LauncherIcons.java @@ -0,0 +1,113 @@ +/* + * 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.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +/** + * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons. + * @hide + */ +public final class LauncherIcons { + + private final Paint mPaint = new Paint(); + private final Canvas mCanvas = new Canvas(); + + private static final int KEY_SHADOW_ALPHA = 61; + private static final int AMBIENT_SHADOW_ALPHA = 30; + private static final float BLUR_FACTOR = 0.5f / 48; + private int mShadowInset; + private Bitmap mShadowBitmap; + private int mIconSize; + private Resources mRes; + + public LauncherIcons(Context context) { + mRes = context.getResources(); + DisplayMetrics metrics = mRes.getDisplayMetrics(); + mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT; + mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, + Paint.FILTER_BITMAP_FLAG)); + mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size); + } + + /** + * Draw the drawable into a bitmap. + */ + public Bitmap createIconBitmap(Drawable icon) { + final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); + mPaint.setAlpha(255); + mCanvas.setBitmap(bitmap); + int iconInset = 0; + if (mShadowBitmap != null) { + mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint); + iconInset = mShadowInset; + } + + icon.setBounds(iconInset, iconInset, mIconSize - iconInset, + mIconSize - iconInset); + icon.draw(mCanvas); + mCanvas.setBitmap(null); + return bitmap; + } + + public Drawable wrapIconDrawableWithShadow(Drawable drawable) { + if (!(drawable instanceof AdaptiveIconDrawable)) { + return drawable; + } + AdaptiveIconDrawable d = + (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate(); + getShadowBitmap(d); + Bitmap iconbitmap = createIconBitmap(d); + return new BitmapDrawable(mRes, iconbitmap); + } + + private Bitmap getShadowBitmap(AdaptiveIconDrawable d) { + if (mShadowBitmap != null) { + return mShadowBitmap; + } + + int shadowSize = mIconSize - mShadowInset; + mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8); + mCanvas.setBitmap(mShadowBitmap); + + // Draw key shadow + mPaint.setColor(Color.TRANSPARENT); + float blur = BLUR_FACTOR * mIconSize; + mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24); + d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset); + mCanvas.drawPath(d.getIconMask(), mPaint); + + // Draw ambient shadow + mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24); + d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize); + mCanvas.drawPath(d.getIconMask(), mPaint); + mPaint.clearShadowLayer(); + + return mShadowBitmap; + } +} diff --git a/core/java/android/util/MergedConfiguration.aidl b/core/java/android/util/MergedConfiguration.aidl new file mode 100644 index 000000000000..c24dbbec68a6 --- /dev/null +++ b/core/java/android/util/MergedConfiguration.aidl @@ -0,0 +1,19 @@ +/* + * 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; + +parcelable MergedConfiguration;
\ No newline at end of file diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java new file mode 100644 index 000000000000..d94af8a68fc1 --- /dev/null +++ b/core/java/android/util/MergedConfiguration.java @@ -0,0 +1,122 @@ +/* + * 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.annotation.NonNull; +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Container that holds global and override config and their merge product. + * Merged configuration updates automatically whenever global or override configs are updated via + * setters. + * + * {@hide} + */ +public class MergedConfiguration implements Parcelable { + + private Configuration mGlobalConfig = new Configuration(); + private Configuration mOverrideConfig = new Configuration(); + private Configuration mMergedConfig = new Configuration(); + + public MergedConfiguration() { + } + + public MergedConfiguration(Configuration globalConfig, Configuration overrideConfig) { + setConfiguration(globalConfig, overrideConfig); + } + + public MergedConfiguration(MergedConfiguration mergedConfiguration) { + setConfiguration(mergedConfiguration.getGlobalConfiguration(), + mergedConfiguration.getOverrideConfiguration()); + } + + private MergedConfiguration(Parcel in) { + readFromParcel(in); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mGlobalConfig, flags); + dest.writeParcelable(mOverrideConfig, flags); + dest.writeParcelable(mMergedConfig, flags); + } + + public void readFromParcel(Parcel source) { + mGlobalConfig = source.readParcelable(Configuration.class.getClassLoader()); + mOverrideConfig = source.readParcelable(Configuration.class.getClassLoader()); + mMergedConfig = source.readParcelable(Configuration.class.getClassLoader()); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator<MergedConfiguration> CREATOR = new Creator<MergedConfiguration>() { + @Override + public MergedConfiguration createFromParcel(Parcel in) { + return new MergedConfiguration(in); + } + + @Override + public MergedConfiguration[] newArray(int size) { + return new MergedConfiguration[size]; + } + }; + + /** + * Update global and override configurations. + * Merged configuration will automatically be updated. + * @param globalConfig New global configuration. + * @param overrideConfig New override configuration. + */ + public void setConfiguration(Configuration globalConfig, Configuration overrideConfig) { + mGlobalConfig.setTo(globalConfig); + mOverrideConfig.setTo(overrideConfig); + updateMergedConfig(); + } + + /** + * @return Stored global configuration value. + */ + @NonNull + public Configuration getGlobalConfiguration() { + return mGlobalConfig; + } + + /** + * @return Stored override configuration value. + */ + public Configuration getOverrideConfiguration() { + return mOverrideConfig; + } + + /** + * @return Stored merged configuration value. + */ + public Configuration getMergedConfiguration() { + return mMergedConfig; + } + + /** Update merged config when global or override config changes. */ + private void updateMergedConfig() { + mMergedConfig.setTo(mGlobalConfig); + mMergedConfig.updateFrom(mOverrideConfig); + } +} diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java index e59937dae055..ca54bef1e780 100644 --- a/core/java/android/view/AccessibilityIterators.java +++ b/core/java/android/view/AccessibilityIterators.java @@ -16,7 +16,6 @@ package android.view; -import android.content.ComponentCallbacks; import android.content.res.Configuration; import java.text.BreakIterator; @@ -65,7 +64,7 @@ public final class AccessibilityIterators { } static class CharacterTextSegmentIterator extends AbstractTextSegmentIterator - implements ComponentCallbacks { + implements ViewRootImpl.ConfigChangedCallback { private static CharacterTextSegmentIterator sInstance; private Locale mLocale; @@ -144,19 +143,14 @@ public final class AccessibilityIterators { } @Override - public void onConfigurationChanged(Configuration newConfig) { - Locale locale = newConfig.locale; + public void onConfigurationChanged(Configuration globalConfig) { + final Locale locale = globalConfig.getLocales().get(0); if (!mLocale.equals(locale)) { mLocale = locale; onLocaleChanged(locale); } } - @Override - public void onLowMemory() { - /* ignore */ - } - protected void onLocaleChanged(Locale locale) { mImpl = BreakIterator.getCharacterInstance(locale); } diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 14b2abec2adb..611cc6337fb4 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -17,7 +17,6 @@ package android.view; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -26,6 +25,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import com.android.internal.os.IResultReceiver; +import android.util.MergedConfiguration; /** * API back to a client window that the Window Manager uses to inform it of @@ -49,8 +49,8 @@ oneway interface IWindow { void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets, in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw, - in Configuration newConfig, in Rect backDropFrame, boolean forceLayout, - boolean alwaysConsumeNavBar, int displayId); + in MergedConfiguration newMergedConfiguration, in Rect backDropFrame, + boolean forceLayout, boolean alwaysConsumeNavBar, int displayId); void moved(int newX, int newY); void dispatchAppVisibility(boolean visible); void dispatchGetNewSurface(); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 7e6af11a62c7..51d65144f260 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -11,17 +11,17 @@ ** 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 +** See the License for the specific language governing permissions and ** limitations under the License. */ package android.view; import android.content.ClipData; -import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; +import android.util.MergedConfiguration; import android.view.InputChannel; import android.view.IWindow; import android.view.IWindowId; @@ -83,9 +83,9 @@ interface IWindowSession { * treat as real display. Example of such area is a chin in some models of wearable devices. * @param outBackdropFrame Rect which is used draw the resizing background during a resize * operation. - * @param outConfiguration New configuration of window, if it is now - * becoming visible and the global configuration has changed since it - * was last displayed. + * @param outMergedConfiguration New config container that holds global, override and merged + * config for window, if it is now becoming visible and the merged configuration has changed + * since it was last displayed. * @param outSurface Object in which is placed the new display surface. * * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS}, @@ -95,8 +95,8 @@ interface IWindowSession { int requestedWidth, int requestedHeight, int viewVisibility, int flags, out Rect outFrame, out Rect outOverscanInsets, out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, - out Rect outOutsets, out Rect outBackdropFrame, out Configuration outConfig, - out Surface outSurface); + out Rect outOutsets, out Rect outBackdropFrame, + out MergedConfiguration outMergedConfiguration, out Surface outSurface); /* * Notify the window manager that an application is relaunching and diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 6d320ef32b0d..824e035697fc 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -16,8 +16,9 @@ package android.view; -import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER; +import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER; import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER; import android.content.Context; @@ -28,6 +29,7 @@ import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.SystemClock; @@ -777,6 +779,31 @@ public class SurfaceView extends View { } /** + * This method still exists only for compatibility reasons because some applications have relied + * on this method via reflection. See Issue 36345857 for details. + * + * @deprecated No platform code is using this method anymore. + * @hide + */ + @Deprecated + public void setWindowType(int type) { + if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) { + throw new UnsupportedOperationException( + "SurfaceView#setWindowType() has never been a public API."); + } + + if (type == TYPE_APPLICATION_PANEL) { + Log.e(TAG, "If you are calling SurfaceView#setWindowType(TYPE_APPLICATION_PANEL) " + + "just to make the SurfaceView to be placed on top of its window, you must " + + "call setZOrderOnTop(true) instead.", new Throwable()); + setZOrderOnTop(true); + return; + } + Log.e(TAG, "SurfaceView#setWindowType(int) is deprecated and now does nothing. " + + "type=" + type, new Throwable()); + } + + /** * Check to see if the surface has fixed size dimensions or if the surface's * dimensions are dimensions are dependent on its current layout. * diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 80f6c3249428..583dad48295c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2749,13 +2749,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * x * NO LONGER NEEDED, SHOULD BE REUSED * * 1 PFLAG3_FINGER_DOWN * 1 PFLAG3_FOCUSED_BY_DEFAULT -<<<<<<< HEAD * 11 PFLAG3_AUTO_FILL_MODE_MASK * 11 PFLAG3_IMPORTANT_FOR_AUTOFILL -======= - * 11 PFLAG3_AUTOFILL_MODE_MASK - * xx * NO LONGER NEEDED, SHOULD BE REUSED * ->>>>>>> Replaced auto-fill by autofill to keep it consistent with API style. * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED * 1 PFLAG3_TEMPORARY_DETACH @@ -7384,13 +7379,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>When implementing this method, subclasses must follow the rules below: * * <ol> - * <li>Also implement {@link #autofillVirtual(int, AutofillValue)} to autofill the virtual + * <li>Also implement {@link #autofill(int, AutofillValue)} to autofill the virtual * children. * <li>Call - * {@link android.view.autofill.AutofillManager#notifyVirtualViewEntered} and - * {@link android.view.autofill.AutofillManager#notifyVirtualViewExited(View, int)} + * {@link android.view.autofill.AutofillManager#notifyViewEntered} and + * {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} * when the focus inside the view changed. - * <li>Call {@link android.view.autofill.AutofillManager#notifyVirtualValueChanged(View, int, + * <li>Call {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, * AutofillValue)} when the value of a child changed. * <li>Call {@link AutofillManager#commit()} when the autofill context * of the view structure changed and you want the current autofill interaction if such @@ -7445,8 +7440,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * </pre> * * @param value value to be autofilled. + * + * @return {@code true} if the view was successfully autofilled, {@code false} otherwise */ - public void autofill(@SuppressWarnings("unused") AutofillValue value) { + public boolean autofill(@SuppressWarnings("unused") AutofillValue value) { + return false; } /** @@ -7457,14 +7455,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param value value to be autofilled. * @param virtualId id identifying the virtual child inside the custom view. + * + * @return {@code true} if the view was successfully autofilled, {@code false} otherwise */ - public void autofillVirtual(@SuppressWarnings("unused") int virtualId, + public boolean autofill(@SuppressWarnings("unused") int virtualId, @SuppressWarnings("unused") AutofillValue value) { + return false; } /** * Describes the autofill type that should be used on calls to - * {@link #autofill(AutofillValue)} and {@link #autofillVirtual(int, AutofillValue)}. + * {@link #autofill(AutofillValue)} and {@link #autofill(int, AutofillValue)}. * * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it (and * {@link #autofill(AutofillValue)} to support the Autofill Framework. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index ed4238501c5a..168178702ebf 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.Display.INVALID_DISPLAY; import static android.view.View.PFLAG_DRAW_ANIMATION; import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER; import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM; @@ -28,10 +29,10 @@ import android.Manifest; import android.animation.LayoutTransition; import android.annotation.NonNull; import android.app.ActivityManager; +import android.app.ActivityThread; import android.app.ResourcesManager; import android.content.ClipData; import android.content.ClipDescription; -import android.content.ComponentCallbacks; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; @@ -67,6 +68,7 @@ import android.os.Trace; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.Log; +import android.util.MergedConfiguration; import android.util.Slog; import android.util.TimeUtils; import android.util.TypedValue; @@ -161,7 +163,44 @@ public final class ViewRootImpl implements ViewParent, static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList(); static boolean sFirstDrawComplete = false; - static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList(); + /** + * Callback for notifying about global configuration changes. + */ + public interface ConfigChangedCallback { + + /** Notifies about global config change. */ + void onConfigurationChanged(Configuration globalConfig); + } + + private static final ArrayList<ConfigChangedCallback> sConfigCallbacks = new ArrayList<>(); + + /** + * Callback for notifying activities about override configuration changes. + */ + public interface ActivityConfigCallback { + + /** + * Notifies about override config change and/or move to different display. + * @param overrideConfig New override config to apply to activity. + * @param newDisplayId New display id, {@link Display#INVALID_DISPLAY} if not changed. + */ + void onConfigurationChanged(Configuration overrideConfig, int newDisplayId); + } + + /** + * Callback used to notify corresponding activity about override configuration change and make + * sure that all resources are set correctly before updating the ViewRootImpl's internal state. + */ + private ActivityConfigCallback mActivityConfigCallback; + + /** + * Used when configuration change first updates the config of corresponding activity. + * In that case we receive a call back from {@link ActivityThread} and this flag is used to + * preserve the initial value. + * + * @see #performConfigurationChange(Configuration, Configuration, boolean, int) + */ + private boolean mForceNextConfigUpdate; /** * Signals that compatibility booleans have been initialized according to @@ -344,8 +383,12 @@ public final class ViewRootImpl implements ViewParent, private WindowInsets mLastWindowInsets; - final Configuration mLastConfiguration = new Configuration(); - final Configuration mPendingConfiguration = new Configuration(); + /** Last applied configuration obtained from resources. */ + private final Configuration mLastConfigurationFromResources = new Configuration(); + /** Last configuration reported from WM or via {@link #MSG_UPDATE_CONFIGURATION}. */ + private final MergedConfiguration mLastReportedMergedConfiguration = new MergedConfiguration(); + /** Configurations waiting to be applied. */ + private final MergedConfiguration mPendingMergedConfiguration = new MergedConfiguration(); boolean mScrollMayChange; @SoftInputModeFlags @@ -464,7 +507,7 @@ public final class ViewRootImpl implements ViewParent, mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); if (!sCompatibilityDone) { - sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.O; + sAlwaysAssignFocus = true; sCompatibilityDone = true; } @@ -480,12 +523,18 @@ public final class ViewRootImpl implements ViewParent, } } - public static void addConfigCallback(ComponentCallbacks callback) { + /** Add static config callback to be notified about global config changes. */ + public static void addConfigCallback(ConfigChangedCallback callback) { synchronized (sConfigCallbacks) { sConfigCallbacks.add(callback); } } + /** Add activity config callback to be notified about override config changes. */ + public void setActivityConfigCallback(ActivityConfigCallback callback) { + mActivityConfigCallback = callback; + } + public void addWindowCallbacks(WindowCallbacks callback) { if (USE_MT_RENDERER) { synchronized (mWindowCallbacks) { @@ -1558,6 +1607,7 @@ public final class ViewRootImpl implements ViewParent, mFullRedrawNeeded = true; mLayoutRequested = true; + final Configuration config = mContext.getResources().getConfiguration(); if (shouldUseDisplaySize(lp)) { // NOTE -- system code, won't try to do compat mode. Point size = new Point(); @@ -1565,7 +1615,6 @@ public final class ViewRootImpl implements ViewParent, desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { - Configuration config = mContext.getResources().getConfiguration(); desiredWindowWidth = dipToPx(config.screenWidthDp); desiredWindowHeight = dipToPx(config.screenHeightDp); } @@ -1577,11 +1626,11 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mHasWindowFocus = false; mAttachInfo.mWindowVisibility = viewVisibility; mAttachInfo.mRecomputeGlobalAttributes = false; - mLastConfiguration.setTo(host.getResources().getConfiguration()); + mLastConfigurationFromResources.setTo(config); mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; // Set the layout direction if it has not been set before (inherit is the default) if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { - host.setLayoutDirection(mLastConfiguration.getLayoutDirection()); + host.setLayoutDirection(config.getLayoutDirection()); } host.dispatchAttachedToWindow(mAttachInfo, 0); mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); @@ -1826,11 +1875,14 @@ public final class ViewRootImpl implements ViewParent, + " outsets=" + mPendingOutsets.toShortString() + " surface=" + mSurface); - if (mPendingConfiguration.seq != 0) { + final Configuration pendingMergedConfig = + mPendingMergedConfiguration.getMergedConfiguration(); + if (pendingMergedConfig.seq != 0) { if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " - + mPendingConfiguration); - updateConfiguration(new Configuration(mPendingConfiguration), !mFirst); - mPendingConfiguration.seq = 0; + + pendingMergedConfig); + performConfigurationChange(mPendingMergedConfiguration, !mFirst, + INVALID_DISPLAY /* same display */); + pendingMergedConfig.seq = 0; updatedConfiguration = true; } @@ -3388,43 +3440,82 @@ public final class ViewRootImpl implements ViewParent, unscheduleTraversals(); } - void updateConfiguration(Configuration config, boolean force) { + /** + * Notifies all callbacks that configuration and/or display has changed and updates internal + * state. + * @param mergedConfiguration New global and override config in {@link MergedConfiguration} + * container. + * @param force Flag indicating if we should force apply the config. + * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} if not + * changed. + */ + private void performConfigurationChange(MergedConfiguration mergedConfiguration, boolean force, + int newDisplayId) { + if (mergedConfiguration == null) { + throw new IllegalArgumentException("No merged config provided."); + } + + Configuration globalConfig = mergedConfiguration.getGlobalConfiguration(); + final Configuration overrideConfig = mergedConfiguration.getOverrideConfiguration(); if (DEBUG_CONFIGURATION) Log.v(mTag, - "Applying new config to window " - + mWindowAttributes.getTitle() - + ": " + config); + "Applying new config to window " + mWindowAttributes.getTitle() + + ", globalConfig: " + globalConfig + + ", overrideConfig: " + overrideConfig); - CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); + final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { - config = new Configuration(config); - ci.applyToConfiguration(mNoncompatDensity, config); + globalConfig = new Configuration(globalConfig); + ci.applyToConfiguration(mNoncompatDensity, globalConfig); } synchronized (sConfigCallbacks) { for (int i=sConfigCallbacks.size()-1; i>=0; i--) { - sConfigCallbacks.get(i).onConfigurationChanged(config); + sConfigCallbacks.get(i).onConfigurationChanged(globalConfig); } } - if (mView != null) { - // At this point the resources have been updated to - // have the most recent config, whatever that is. Use - // the one in them which may be newer. - final Resources localResources = mView.getResources(); - config = localResources.getConfiguration(); - if (force || mLastConfiguration.diff(config) != 0) { - // Update the display with new DisplayAdjustments. - mDisplay = ResourcesManager.getInstance().getAdjustedDisplay( - mDisplay.getDisplayId(), localResources); - final int lastLayoutDirection = mLastConfiguration.getLayoutDirection(); - final int currentLayoutDirection = config.getLayoutDirection(); - mLastConfiguration.setTo(config); - if (lastLayoutDirection != currentLayoutDirection && - mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { - mView.setLayoutDirection(currentLayoutDirection); - } - mView.dispatchConfigurationChanged(config); + mLastReportedMergedConfiguration.setConfiguration(globalConfig, overrideConfig); + + mForceNextConfigUpdate = force; + if (mActivityConfigCallback != null) { + // An activity callback is set - notify it about override configuration update. + // This basically initiates a round trip to ActivityThread and back, which will ensure + // that corresponding activity and resources are updated before updating inner state of + // ViewRootImpl. Eventually it will call #updateConfiguration(). + mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId); + } else { + // There is no activity callback - update the configuration right away. + updateConfiguration(); + } + mForceNextConfigUpdate = false; + } + + /** + * Update display and views if last applied merged configuration changed. + */ + public void updateConfiguration() { + if (mView == null) { + return; + } + + // At this point the resources have been updated to + // have the most recent config, whatever that is. Use + // the one in them which may be newer. + final Resources localResources = mView.getResources(); + final Configuration config = localResources.getConfiguration(); + if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) { + // Update the display with new DisplayAdjustments. + mDisplay = ResourcesManager.getInstance().getAdjustedDisplay( + mDisplay.getDisplayId(), localResources); + + final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection(); + final int currentLayoutDirection = config.getLayoutDirection(); + mLastConfigurationFromResources.setTo(config); + if (lastLayoutDirection != currentLayoutDirection + && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { + mView.setLayoutDirection(currentLayoutDirection); } + mView.dispatchConfigurationChanged(config); } } @@ -3582,13 +3673,16 @@ public final class ViewRootImpl implements ViewParent, if (mAdded) { SomeArgs args = (SomeArgs) msg.obj; - if (mDisplay.getDisplayId() != args.argi3) { - onMovedToDisplay(args.argi3); + final int displayId = args.argi3; + final boolean displayChanged = mDisplay.getDisplayId() != displayId; + if (displayChanged) { + onMovedToDisplay(displayId); } - Configuration config = (Configuration) args.arg4; - if (config != null) { - updateConfiguration(config, false); + final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4; + if (mergedConfiguration != null) { + performConfigurationChange(mergedConfiguration, false /* force */, + displayChanged ? displayId : INVALID_DISPLAY /* same display */); } final boolean framesChanged = !mWinFrame.equals(args.arg1) @@ -3759,11 +3853,19 @@ public final class ViewRootImpl implements ViewParent, handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo) msg.obj); } break; case MSG_UPDATE_CONFIGURATION: { - Configuration config = (Configuration)msg.obj; - if (config.isOtherSeqNewer(mLastConfiguration)) { - config = mLastConfiguration; + Configuration config = (Configuration) msg.obj; + if (config.isOtherSeqNewer( + mLastReportedMergedConfiguration.getMergedConfiguration())) { + // If we already have a newer merged config applied - use its global part. + config = mLastReportedMergedConfiguration.getGlobalConfiguration(); } - updateConfiguration(config, false); + + // Use the newer global config and last reported override config. + mPendingMergedConfiguration.setConfiguration(config, + mLastReportedMergedConfiguration.getOverrideConfiguration()); + + performConfigurationChange(mPendingMergedConfiguration, false /* force */, + INVALID_DISPLAY /* same display */); } break; case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { setAccessibilityFocus(null, null); @@ -5902,7 +6004,7 @@ public final class ViewRootImpl implements ViewParent, if (params != null) { if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); } - mPendingConfiguration.seq = 0; + mPendingMergedConfiguration.getMergedConfiguration().seq = 0; //Log.d(mTag, ">>>>>> CALLING relayout"); if (params != null && mOrigWindowType != params.type) { // For compatibility with old apps, don't crash here. @@ -5918,8 +6020,8 @@ public final class ViewRootImpl implements ViewParent, (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, - mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration, - mSurface); + mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, + mPendingMergedConfiguration, mSurface); mPendingAlwaysConsumeNavBar = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0; @@ -6199,9 +6301,9 @@ public final class ViewRootImpl implements ViewParent, } } - public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, + private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, - Configuration newConfig, Rect backDropFrame, boolean forceLayout, + MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString() + " contentInsets=" + contentInsets.toShortString() @@ -6233,7 +6335,8 @@ public final class ViewRootImpl implements ViewParent, args.arg1 = sameProcessCall ? new Rect(frame) : frame; args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets; args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets; - args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig; + args.arg4 = sameProcessCall && mergedConfiguration != null + ? new MergedConfiguration(mergedConfiguration) : null; args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets; args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets; args.arg7 = sameProcessCall ? new Rect(outsets) : outsets; @@ -7243,13 +7346,13 @@ public final class ViewRootImpl implements ViewParent, @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, - Configuration newConfig, Rect backDropFrame, boolean forceLayout, + MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, - visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame, - forceLayout, alwaysConsumeNavBar, displayId); + visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration, + backDropFrame, forceLayout, alwaysConsumeNavBar, displayId); } } diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 38c7738b4bac..4168756e04f3 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -275,13 +275,12 @@ public abstract class ViewStructure { * {@link #addChildCount(int)} and {@link #setChildCount(int)}. * @param virtualId an opaque ID to the Android System (although it could be meaningful to the * {@link View} creating the {@link ViewStructure}), but it's the same id used on - * {@link View#autofillVirtual(int, AutofillValue)}. + * {@link View#autofill(int, AutofillValue)}. * @param flags currently {@code 0}. * * @return Returns an fresh {@link ViewStructure} ready to be filled in. */ - // TODO(b/33197203, b/33802548): add CTS/unit test - public abstract ViewStructure newChildForAutofill(int index, int virtualId, int flags); + public abstract ViewStructure newChild(int index, int virtualId, int flags); /** * Like {@link #newChild}, but allows the caller to asynchronously populate the returned @@ -294,7 +293,7 @@ public abstract class ViewStructure { public abstract ViewStructure asyncNewChild(int index); /** - * Like {@link #newChildForAutofill(int, int, int)}, but allows the caller to asynchronously + * Like {@link #newChild(int, int, int)}, but allows the caller to asynchronously * populate the returned child. * * <p>It can transfer the returned {@link ViewStructure} to another thread for it to build its @@ -307,13 +306,12 @@ public abstract class ViewStructure { * {@link #addChildCount(int)} and {@link #setChildCount(int)}. * @param virtualId an opaque ID to the Android System (although it could be meaningful to the * {@link View} creating the {@link ViewStructure}), but it's the same id used on - * {@link View#autofillVirtual(int, AutofillValue)}. + * {@link View#autofill(int, AutofillValue)}. * @param flags currently {@code 0}. * * @return Returns an fresh {@link ViewStructure} ready to be filled in. */ - // TODO(b/33197203, b/33802548): add CTS/unit test - public abstract ViewStructure asyncNewChildForAutofill(int index, int virtualId, int flags); + public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags); /** * Sets the {@link View#getAutofillType()} that can be used to autofill this node. diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index f036b9cddec4..9ed6371404c4 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -83,7 +83,7 @@ public final class AutofillManager { /** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000; /** @hide */ public static final int FLAG_VALUE_CHANGED = 0x10000000; - private final Rect mTempRect = new Rect(); + @NonNull private final Rect mTempRect = new Rect(); private final IAutoFillManager mService; private IAutoFillManagerClient mServiceClient; @@ -196,6 +196,9 @@ public final class AutofillManager { ensureServiceClientAddedIfNeeded(); if (!mEnabled) { + if (mCallback != null) { + mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } return; } @@ -236,11 +239,13 @@ public final class AutofillManager { * @param childId id identifying the virtual child inside the view. * @param bounds child boundaries, relative to the top window. */ - public void notifyVirtualViewEntered(@NonNull View view, int childId, - @NonNull Rect bounds) { + public void notifyViewEntered(@NonNull View view, int childId, @NonNull Rect bounds) { ensureServiceClientAddedIfNeeded(); if (!mEnabled) { + if (mCallback != null) { + mCallback.onAutofillEvent(view, childId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } return; } @@ -261,7 +266,7 @@ public final class AutofillManager { * @param view the {@link View} whose descendant is the virtual view. * @param childId id identifying the virtual child inside the view. */ - public void notifyVirtualViewExited(@NonNull View view, int childId) { + public void notifyViewExited(@NonNull View view, int childId) { ensureServiceClientAddedIfNeeded(); if (mEnabled && mHasSession) { @@ -295,7 +300,7 @@ public final class AutofillManager { * @param childId id identifying the virtual child inside the parent view. * @param value new value of the child. */ - public void notifyVirtualValueChanged(View view, int childId, AutofillValue value) { + public void notifyValueChanged(View view, int childId, AutofillValue value) { if (!mEnabled || !mHasSession) { return; } @@ -371,8 +376,8 @@ public final class AutofillManager { return new AutofillId(parent.getAccessibilityViewId(), childId); } - private void startSession(AutofillId id, IBinder windowToken, Rect bounds, - AutofillValue value, int flags) { + private void startSession(@NonNull AutofillId id, @NonNull IBinder windowToken, + @NonNull Rect bounds, @NonNull AutofillValue value, int flags) { if (DEBUG) { Log.d(TAG, "startSession(): id=" + id + ", bounds=" + bounds + ", value=" + value + ", flags=" + flags); @@ -381,8 +386,8 @@ public final class AutofillManager { try { mService.startSession(mContext.getActivityToken(), windowToken, mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), - mCallback != null, flags); - final AutofillClient client = getClient(); + mCallback != null, flags, mContext.getOpPackageName()); + AutofillClient client = getClient(); if (client != null) { client.resetableStateAvailable(); } @@ -503,7 +508,7 @@ public final class AutofillManager { return; } if (id.isVirtual()) { - mCallback.onAutofillEventVirtual(view, id.getVirtualChildId(), event); + mCallback.onAutofillEvent(view, id.getVirtualChildId(), event); } else { mCallback.onAutofillEvent(view, event); } @@ -539,13 +544,23 @@ public final class AutofillManager { public static final int EVENT_INPUT_HIDDEN = 2; /** + * The auto-fill input UI affordance associated with the view won't be shown because + * autofill is not available. + * + * <p>If the view provides its own auto-complete UI affordance but was not displaying it + * to avoid flickering, it could shown it upon receiving this event. + */ + public static final int EVENT_INPUT_UNAVAILABLE = 3; + + /** * Called after a change in the autofill state associated with a view. * * @param view view associated with the change. * * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}. */ - public void onAutofillEvent(@NonNull View view, @AutofillEventType int event) {} + public void onAutofillEvent(@NonNull View view, @AutofillEventType int event) { + } /** * Called after a change in the autofill state associated with a virtual view. @@ -555,8 +570,8 @@ public final class AutofillManager { * * @param event currently either {@link #EVENT_INPUT_SHOWN} or {@link #EVENT_INPUT_HIDDEN}. */ - public void onAutofillEventVirtual(@NonNull View view, int childId, - @AutofillEventType int event) {} + public void onAutofillEvent(@NonNull View view, int childId, @AutofillEventType int event) { + } } private static final class AutofillManagerClient extends IAutoFillManagerClient.Stub { diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 85b05e585318..97210cc919a5 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -32,7 +32,7 @@ interface IAutoFillManager { boolean addClient(in IAutoFillManagerClient client, int userId); oneway void startSession(in IBinder activityToken, IBinder windowToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, - boolean hasCallback, int flags); + boolean hasCallback, int flags, String packageName); oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds, in AutofillValue value, int flags, int userId); oneway void finishSession(in IBinder activityToken, int userId); diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java index 020e80a29134..fae574289b88 100644 --- a/core/java/android/widget/AbsSpinner.java +++ b/core/java/android/widget/AbsSpinner.java @@ -514,14 +514,15 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isList()) { setSelection(value.getListValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + return true; } @Override diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index 899a824489e3..9dc61ab56b34 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -584,14 +584,16 @@ public abstract class CompoundButton extends Button implements Checkable { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isToggle()) { setChecked(value.getToggleValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index f63573f4f3fe..7d04f355f251 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -775,14 +775,16 @@ public class DatePicker extends FrameLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isDate()) { mDelegate.updateDate(value.getDateValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java index 5e8279a3e7c9..a7574c7a45ae 100644 --- a/core/java/android/widget/RadioGroup.java +++ b/core/java/android/widget/RadioGroup.java @@ -426,23 +426,24 @@ public class RadioGroup extends LinearLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; int index; if (value.isList()) { index = value.getListValue(); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); - return; + return false; } final View child = getChildAt(index); if (child == null) { Log.w(VIEW_LOG_TAG, "RadioGroup.autoFill(): no child with index " + index); - return; + return false; } check(child.getId()); + return true; } @Override diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c5c317d671ef..26edc436b2f8 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -10028,14 +10028,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void autofill(AutofillValue value) { + public boolean autofill(AutofillValue value) { if (value.isText()) { if (isTextEditable()) { setText(value.getTextValue(), mBufferType, true, 0); + return true; } } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return false; } @Override diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index cfa78b53dd91..1e97e3ba5134 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -530,14 +530,16 @@ public class TimePicker extends FrameLayout { } @Override - public void autofill(AutofillValue value) { - if (!isEnabled()) return; + public boolean autofill(AutofillValue value) { + if (!isEnabled()) return false; if (value.isDate()) { mDelegate.setDate(value.getDateValue()); } else { Log.w(LOG_TAG, value + " could not be autofilled into " + this); } + + return true; } @Override diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index ec3aac21cb19..c840f26a0d53 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -48,12 +48,12 @@ public class SystemNotificationChannels { List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>(); channelsList.add(new NotificationChannel( VIRTUAL_KEYBOARD, - R.string.notification_channel_virtual_keyboard, + context.getString(R.string.notification_channel_virtual_keyboard), NotificationManager.IMPORTANCE_LOW)); final NotificationChannel physicalKeyboardChannel = new NotificationChannel( PHYSICAL_KEYBOARD, - R.string.notification_channel_physical_keyboard, + context.getString(R.string.notification_channel_physical_keyboard), NotificationManager.IMPORTANCE_DEFAULT); physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT); @@ -61,32 +61,32 @@ public class SystemNotificationChannels { channelsList.add(new NotificationChannel( SECURITY, - R.string.notification_channel_security, + context.getString(R.string.notification_channel_security), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( CAR_MODE, - R.string.notification_channel_car_mode, + context.getString(R.string.notification_channel_car_mode), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( DEVELOPER, - R.string.notification_channel_developer, + context.getString(R.string.notification_channel_developer), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( UPDATES, - R.string.notification_channel_updates, + context.getString(R.string.notification_channel_updates), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( NETWORK_STATUS, - R.string.notification_channel_network_status, + context.getString(R.string.notification_channel_network_status), NotificationManager.IMPORTANCE_LOW)); final NotificationChannel networkAlertsChannel = new NotificationChannel( NETWORK_ALERTS, - R.string.notification_channel_network_alerts, + context.getString(R.string.notification_channel_network_alerts), NotificationManager.IMPORTANCE_HIGH); networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT); @@ -94,17 +94,17 @@ public class SystemNotificationChannels { channelsList.add(new NotificationChannel( VPN, - R.string.notification_channel_vpn, + context.getString(R.string.notification_channel_vpn), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( DEVICE_ADMIN, - R.string.notification_channel_device_admin, + context.getString(R.string.notification_channel_device_admin), NotificationManager.IMPORTANCE_LOW)); final NotificationChannel alertsChannel = new NotificationChannel( ALERTS, - R.string.notification_channel_alerts, + context.getString(R.string.notification_channel_alerts), NotificationManager.IMPORTANCE_DEFAULT); alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT); @@ -112,12 +112,12 @@ public class SystemNotificationChannels { channelsList.add(new NotificationChannel( RETAIL_MODE, - R.string.notification_channel_retail_mode, + context.getString(R.string.notification_channel_retail_mode), NotificationManager.IMPORTANCE_LOW)); channelsList.add(new NotificationChannel( USB, - R.string.notification_channel_usb, + context.getString(R.string.notification_channel_usb), NotificationManager.IMPORTANCE_MIN)); nm.createNotificationChannels(channelsList); @@ -128,7 +128,7 @@ public class SystemNotificationChannels { final NotificationManager nm = context.getSystemService(NotificationManager.class); nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel( ACCOUNT, - R.string.notification_channel_account, + context.getString(R.string.notification_channel_account), NotificationManager.IMPORTANCE_LOW))); } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 96468abd9047..0a9faa15dcc2 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -142,6 +142,21 @@ public class WrapperInit { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper"); } - RuntimeInit.applicationInit(targetSdkVersion, argv, null); + // Check whether the first argument is a "-cp" in argv, and assume the next argument is the + // classpath. If found, create a PathClassLoader and use it for applicationInit. + ClassLoader classLoader = null; + if (argv != null && argv.length > 2 && argv[0].equals("-cp")) { + classLoader = ZygoteInit.createPathClassLoader(argv[1], targetSdkVersion); + + // Install this classloader as the context classloader, too. + Thread.currentThread().setContextClassLoader(classLoader); + + // Remove the classpath from the arguments. + String removedArgs[] = new String[argv.length - 2]; + System.arraycopy(argv, 2, removedArgs, 0, argv.length - 2); + argv = removedArgs; + } + + RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 76d8af1a509d..b2a2fec879e6 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -468,7 +468,8 @@ public class ZygoteInit { String[] amendedArgs = new String[args.length + 2]; amendedArgs[0] = "-cp"; amendedArgs[1] = systemServerClasspath; - System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length); + System.arraycopy(args, 0, amendedArgs, 2, args.length); + args = amendedArgs; } WrapperInit.execApplication(parsedArgs.invokeWith, @@ -477,8 +478,7 @@ public class ZygoteInit { } else { ClassLoader cl = null; if (systemServerClasspath != null) { - cl = createSystemServerClassLoader(systemServerClasspath, - parsedArgs.targetSdkVersion); + cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion); Thread.currentThread().setContextClassLoader(cl); } @@ -493,15 +493,14 @@ public class ZygoteInit { } /** - * Creates a PathClassLoader for the system server. It also creates - * a shared namespace associated with the classloader to let it access - * platform-private native libraries. + * Creates a PathClassLoader for the given class path that is associated with a shared + * namespace, i.e., this classloader can access platform-private native libraries. The + * classloader will use java.library.path as the native library path. */ - private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath, - int targetSdkVersion) { + static PathClassLoader createPathClassLoader(String classPath, int targetSdkVersion) { String libraryPath = System.getProperty("java.library.path"); - return PathClassLoaderFactory.createClassLoader(systemServerClasspath, + return PathClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath, ClassLoader.getSystemClassLoader(), diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index ce51dc4ead9e..361fd3da97c7 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -16,12 +16,12 @@ package com.android.internal.view; -import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.MergedConfiguration; import android.view.DragEvent; import android.view.IWindow; import android.view.IWindowSession; @@ -39,8 +39,9 @@ public class BaseIWindow extends IWindow.Stub { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, - Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig, - Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) { + Rect stableInsets, Rect outsets, boolean reportDraw, + MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, + boolean alwaysConsumeNavBar, int displayId) { if (reportDraw) { try { mSession.finishDrawing(this); diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java index 80207ee854b8..e86932cf3b29 100644 --- a/core/java/com/android/internal/widget/ImageFloatingTextView.java +++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java @@ -115,6 +115,7 @@ public class ImageFloatingTextView extends TextView { // Lets calculate how many lines the given measurement allows us. int availableHeight = height - mPaddingTop - mPaddingBottom; int maxLines = availableHeight / getLineHeight(); + maxLines = Math.max(1, maxLines); if (getMaxLines() > 0) { maxLines = Math.min(getMaxLines(), maxLines); } diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java index b259ad1643f8..1104318763c0 100644 --- a/core/java/com/android/internal/widget/MessagingLinearLayout.java +++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java @@ -16,8 +16,6 @@ package com.android.internal.widget; -import com.android.internal.R; - import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; @@ -28,6 +26,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.RemoteViews; +import com.android.internal.R; + /** * A custom-built layout for the Notification.MessagingStyle. * @@ -119,23 +119,30 @@ public class MessagingLinearLayout extends ViewGroup { } final View child = getChildAt(i); LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); - + ImageFloatingTextView textChild = null; if (child instanceof ImageFloatingTextView) { // Pretend we need the image padding for all views, we don't know which // one will end up needing to do this (might end up not using all the space, // but calculating this exactly would be more expensive). - ((ImageFloatingTextView) child).setNumIndentLines( - mIndentLines == 2 ? 3 : mIndentLines); + textChild = (ImageFloatingTextView) child; + textChild.setNumIndentLines(mIndentLines == 2 ? 3 : mIndentLines); } - measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + int spacing = first ? 0 : mSpacing; + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight + - mPaddingTop - mPaddingBottom + spacing); final int childHeight = child.getMeasuredHeight(); int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin + - lp.bottomMargin + (first ? 0 : mSpacing)); + lp.bottomMargin + spacing); first = false; + boolean measuredTooSmall = false; + if (textChild != null) { + measuredTooSmall = childHeight < textChild.getLayout().getHeight() + + textChild.getPaddingTop() + textChild.getPaddingBottom(); + } - if (newHeight <= targetHeight) { + if (newHeight <= targetHeight && !measuredTooSmall) { totalHeight = newHeight; lp.hide = false; } else { @@ -168,7 +175,15 @@ public class MessagingLinearLayout extends ViewGroup { } boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines)); if (changed || !recalculateVisibility) { - measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, + mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin, + lp.width); + // we want to measure it at most as high as it is currently, otherwise we'll + // drop later lines + final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, + targetHeight - child.getMeasuredHeight(), lp.height); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec);; } imageLines -= textChild.getLineCount(); } diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index 79439e2350ff..5553a3ed22c5 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -30,7 +30,7 @@ using namespace uirenderer; class SkColorFilterGlue { public: - static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) { + static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) { SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle); SkSafeUnref(filter); } @@ -57,19 +57,19 @@ public: }; static const JNINativeMethod colorfilter_methods[] = { - {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer} + {"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref} }; static const JNINativeMethod porterduff_methods[] = { - { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, + { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, }; static const JNINativeMethod lighting_methods[] = { - { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter }, + { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter }, }; static const JNINativeMethod colormatrix_methods[] = { - { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter }, + { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter }, }; int register_android_graphics_ColorFilter(JNIEnv* env) { diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index 1bd233313ca3..678041f85d17 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -404,6 +404,11 @@ static void JHwParcel_native_verifySuccess(JNIEnv *env, jobject thiz) { signalExceptionForError(env, err); } +static void JHwParcel_native_release( + JNIEnv *env, jobject thiz) { + JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */); +} + static void JHwParcel_native_releaseTemporaryStorage( JNIEnv *env, jobject thiz) { JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env); @@ -955,6 +960,10 @@ static JNINativeMethod gMethods[] = { { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V", (void *)JHwParcel_native_writeBuffer }, + + { "release", "()V", + (void *)JHwParcel_native_release }, + }; namespace android { diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 9660de4dbba4..956b7249660f 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -26,7 +26,9 @@ #include <sys/un.h> #include <unistd.h> +#include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/stringprintf.h> #include <android-base/strings.h> // Static whitelist of open paths that the zygote is allowed to keep open. @@ -65,9 +67,10 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { return true; } - static const std::string kFrameworksPrefix = "/system/framework/"; - static const std::string kJarSuffix = ".jar"; - if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) { + static const char* kFrameworksPrefix = "/system/framework/"; + static const char* kJarSuffix = ".jar"; + if (android::base::StartsWith(path, kFrameworksPrefix) + && android::base::EndsWith(path, kJarSuffix)) { return true; } @@ -79,28 +82,31 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap // See AssetManager.cpp for more details on overlay-subdir. - static const std::string kOverlayDir = "/system/vendor/overlay/"; - static const std::string kVendorOverlayDir = "/vendor/overlay"; - static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/"; - static const std::string kApkSuffix = ".apk"; - - if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir) - || StartsWith(path, kVendorOverlayDir)) - && EndsWith(path, kApkSuffix) + static const char* kOverlayDir = "/system/vendor/overlay/"; + static const char* kVendorOverlayDir = "/vendor/overlay"; + static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kApkSuffix = ".apk"; + + if ((android::base::StartsWith(path, kOverlayDir) + || android::base::StartsWith(path, kOverlaySubdir) + || android::base::StartsWith(path, kVendorOverlayDir)) + && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; } - static const std::string kOverlayIdmapPrefix = "/data/resource-cache/"; - static const std::string kOverlayIdmapSuffix = ".apk@idmap"; - if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix) + static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; + static const char* kOverlayIdmapSuffix = ".apk@idmap"; + if (android::base::StartsWith(path, kOverlayIdmapPrefix) + && android::base::EndsWith(path, kOverlayIdmapSuffix) && path.find("/../") == std::string::npos) { return true; } // All regular files that are placed under this path are whitelisted automatically. - static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; - if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) { + static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; + if (android::base::StartsWith(path, kZygoteWhitelistPath) + && path.find("/../") == std::string::npos) { return true; } @@ -111,24 +117,6 @@ FileDescriptorWhitelist::FileDescriptorWhitelist() : whitelist_() { } -// TODO: Call android::base::StartsWith instead of copying the code here. -// static -bool FileDescriptorWhitelist::StartsWith(const std::string& str, - const std::string& prefix) { - return str.compare(0, prefix.size(), prefix) == 0; -} - -// TODO: Call android::base::EndsWith instead of copying the code here. -// static -bool FileDescriptorWhitelist::EndsWith(const std::string& str, - const std::string& suffix) { - if (suffix.size() > str.size()) { - return false; - } - - return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; -} - FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr; // static @@ -174,7 +162,8 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { } std::string file_path; - if (!Readlink(fd, &file_path)) { + const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd); + if (!android::base::Readlink(fd_path, &file_path)) { return NULL; } @@ -299,30 +288,6 @@ FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file is_sock(false) { } -// TODO: Call android::base::Readlink instead of copying the code here. -// static -bool FileDescriptorInfo::Readlink(const int fd, std::string* result) { - char path[64]; - snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); - - // Code copied from android::base::Readlink starts here : - - // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer, - // and truncates to whatever size you do supply, so it can't be used to query. - // We could call lstat first, but that would introduce a race condition that - // we couldn't detect. - // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here. - char buf[4096]; - ssize_t len = readlink(path, buf, sizeof(buf)); - if (len == -1) { - PLOG(ERROR) << "Readlink on " << fd << " failed."; - return false; - } - - result->assign(buf, len); - return true; -} - // static bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { sockaddr_storage ss; diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h index 03298c38dca9..a39e387fde6c 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -59,10 +59,6 @@ class FileDescriptorWhitelist { private: FileDescriptorWhitelist(); - static bool StartsWith(const std::string& str, const std::string& prefix); - - static bool EndsWith(const std::string& str, const std::string& suffix); - static FileDescriptorWhitelist* instance_; std::vector<std::string> whitelist_; @@ -99,8 +95,6 @@ class FileDescriptorInfo { FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags, int fd_flags, int fs_flags, off_t offset); - static bool Readlink(const int fd, std::string* result); - // Returns the locally-bound name of the socket |fd|. Returns true // iff. all of the following hold : // diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c991f22b6294..58e4051b5111 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3593,7 +3593,7 @@ android:permission="android.permission.BIND_JOB_SERVICE" > </service> - <service android:name="com.android.server.BackgroundDexOptJobService" + <service android:name="com.android.server.pm.BackgroundDexOptService" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE"> </service> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 6e0d9dccea0f..385f256f5d1c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1386,6 +1386,9 @@ <!-- Boolean indicating if current platform supports BLE peripheral mode --> <bool name="config_bluetooth_le_peripheral_mode_supported">false</bool> + <!-- Boolean indicating if current platform supports HFP inband ringing --> + <bool name="config_bluetooth_hfp_inband_ringing_support">false</bool> + <!-- Max number of scan filters supported by blutooth controller. 0 if the device does not support hardware scan filters--> <integer translatable="false" name="config_bluetooth_max_scan_filters">0</integer> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 1ed069b2ea02..d1c14e976003 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4567,22 +4567,25 @@ <!-- Accessibility string used for describing the button in time picker that changes the dialog to circular clock mode. [CHAR LIMIT=NONE] --> <string name="time_picker_radial_mode_description">Switch to clock mode for the time input.</string> - <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved - by an auto-fill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] --> + <!-- Accessibility title for the autofill dialog used to select a list of options to autofill an activity. [CHAR LIMIT=NONE] --> + <string name="autofill_picker_accessibility_title">Autofill options</string> + + <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved + by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] --> <string name="autofill_save_title">Save to <xliff:g id="label" example="MyPass">%1$s</xliff:g>?</string> - <!-- Title for the auto-fill save dialog shown when the the contents of the activity can be saved - by an auto-fill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] --> + <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved + by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] --> <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <xliff:g id="label" example="MyPass">%2$s</xliff:g>?</string> - <!-- Label for the auto-fill save button [CHAR LIMIT=NONE] --> + <!-- Label for the autofill save button [CHAR LIMIT=NONE] --> <string name="autofill_save_yes">Save</string> - <!-- Label for the auto-fill cancel button [CHAR LIMIT=NONE] --> + <!-- Label for the autofill cancel button [CHAR LIMIT=NONE] --> <string name="autofill_save_no">No thanks</string> - <!-- Label for the type of data being saved for auto-fill when it represent user credentials with a password [CHAR LIMIT=NONE] --> + <!-- Label for the type of data being saved for autofill when it represent user credentials with a password [CHAR LIMIT=NONE] --> <string name="autofill_save_type_password">password</string> - <!-- Label for the type of data being saved for auto-fill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] --> + <!-- Label for the type of data being saved for autofill when it represent an address (street, city, etc.) [CHAR LIMIT=NONE] --> <string name="autofill_save_type_address">address</string> - <!-- Label for the type of data being saved for auto-fill when it represents a credit card [CHAR LIMIT=NONE] --> + <!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] --> <string name="autofill_save_type_credit_card">credit card</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 07cecbc12467..0d4a407db242 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -242,6 +242,7 @@ <java-symbol type="bool" name="config_bluetooth_address_validation" /> <java-symbol type="bool" name="config_bluetooth_sco_off_call" /> <java-symbol type="bool" name="config_bluetooth_le_peripheral_mode_supported" /> + <java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" /> <java-symbol type="bool" name="config_cellBroadcastAppLinks" /> <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" /> <java-symbol type="bool" name="config_enableAutoPowerModes" /> @@ -2848,6 +2849,7 @@ <java-symbol type="id" name="autofill_save_yes" /> <java-symbol type="id" name="autofill_save_close" /> <java-symbol type="string" name="autofill" /> + <java-symbol type="string" name="autofill_picker_accessibility_title " /> <java-symbol type="string" name="autofill_save_title" /> <java-symbol type="string" name="autofill_save_title_with_type" /> <java-symbol type="string" name="autofill_save_yes" /> diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index fba8e2300607..dbc9e5d55e37 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -40,6 +40,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy LOCAL_PACKAGE_NAME := FrameworksCoreTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java index ac62bf4d69e9..0ca3729dcc0e 100644 --- a/graphics/java/android/graphics/ColorFilter.java +++ b/graphics/java/android/graphics/ColorFilter.java @@ -28,21 +28,51 @@ package android.graphics; */ public class ColorFilter { /** + * @deprecated Use subclass constructors directly instead. + */ + @Deprecated + public ColorFilter() {} + + /** * Holds the pointer to the native SkColorFilter instance. - * - * @hide */ - public long native_instance; + private long mNativeInstance; + + long createNativeInstance() { + return 0; + } + + void discardNativeInstance() { + if (mNativeInstance != 0) { + nSafeUnref(mNativeInstance); + mNativeInstance = 0; + } + } @Override protected void finalize() throws Throwable { try { - super.finalize(); + if (mNativeInstance != 0) { + nSafeUnref(mNativeInstance); + } + mNativeInstance = -1; } finally { - destroyFilter(native_instance); - native_instance = 0; + super.finalize(); + } + } + + /** @hide */ + public long getNativeInstance() { + if (mNativeInstance == -1) { + throw new IllegalStateException("attempting to use a finalized ColorFilter"); + } + + if (mNativeInstance == 0) { + mNativeInstance = createNativeInstance(); } + return mNativeInstance; + } - static native void destroyFilter(long native_instance); + static native void nSafeUnref(long native_instance); } diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java index 1b1849ebb835..6299b2c47ea1 100644 --- a/graphics/java/android/graphics/ColorMatrix.java +++ b/graphics/java/android/graphics/ColorMatrix.java @@ -268,4 +268,21 @@ public class ColorMatrix { m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f; m[10] = 1; m[11] = 1.772f; m[12] = 0; } + + @Override + public boolean equals(Object obj) { + // if (obj == this) return true; -- NaN value would mean matrix != itself + if (!(obj instanceof ColorMatrix)) { + return false; + } + + // we don't use Arrays.equals(), since that considers NaN == NaN + final float[] other = ((ColorMatrix) obj).mArray; + for (int i = 0; i < 20; i++) { + if (other[i] != mArray[i]) { + return false; + } + } + return true; + } } diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index 291c8ff301f4..61f6cc5ba4ee 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -16,6 +16,9 @@ package android.graphics; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** * A color filter that transforms colors through a 4x5 color matrix. This filter * can be used to change the saturation of pixels, convert from YUV to RGB, etc. @@ -32,9 +35,8 @@ public class ColorMatrixColorFilter extends ColorFilter { * the filter, so changes made to the matrix after the filter * is constructed will not be reflected in the filter. */ - public ColorMatrixColorFilter(ColorMatrix matrix) { + public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) { mMatrix.set(matrix); - update(); } /** @@ -44,84 +46,76 @@ public class ColorMatrixColorFilter extends ColorFilter { * matrix. The first 20 entries of the array are copied into * the filter. See ColorMatrix. */ - public ColorMatrixColorFilter(float[] array) { + public ColorMatrixColorFilter(@NonNull float[] array) { if (array.length < 20) { throw new ArrayIndexOutOfBoundsException(); } mMatrix.set(array); - update(); } /** - * Returns the {@link ColorMatrix} used by this filter. The returned - * value is never null. Modifying the returned matrix does not have - * any effect until you call {@link #setColorMatrix(ColorMatrix)}. - * - * @see #setColorMatrix(ColorMatrix) + * Copies the ColorMatrix from the filter into the passed ColorMatrix. * - * @hide + * @param colorMatrix Set to the current value of the filter's ColorMatrix. */ - public ColorMatrix getColorMatrix() { - return mMatrix; + public void getColorMatrix(ColorMatrix colorMatrix) { + colorMatrix.set(mMatrix); } /** - * Specifies the color matrix used by this filter. If the specified - * color matrix is null, this filter's color matrix will be reset to - * the identity matrix. + * Copies the provided color matrix to be used by this filter. * - * @param matrix A {@link ColorMatrix} or null + * If the specified color matrix is null, this filter's color matrix will be reset to the + * identity matrix. * - * @see #getColorMatrix() - * @see android.graphics.ColorMatrix#reset() - * @see #setColorMatrix(float[]) + * @param matrix A {@link ColorMatrix} or null * - * @hide + * @see #getColorMatrix(ColorMatrix) + * @see #setColorMatrixArray(float[]) + * @see ColorMatrix#reset() */ - public void setColorMatrix(ColorMatrix matrix) { + public void setColorMatrix(@Nullable ColorMatrix matrix) { + discardNativeInstance(); if (matrix == null) { mMatrix.reset(); - } else if (matrix != mMatrix) { + } else { mMatrix.set(matrix); } - update(); } /** - * Specifies the color matrix used by this filter. If the specified - * color matrix is null, this filter's color matrix will be reset to - * the identity matrix. + * Copies the provided color matrix to be used by this filter. + * + * If the specified color matrix is null, this filter's color matrix will be reset to the + * identity matrix. * * @param array Array of floats used to transform colors, treated as a 4x5 * matrix. The first 20 entries of the array are copied into * the filter. See {@link ColorMatrix}. * - * @see #getColorMatrix() - * @see android.graphics.ColorMatrix#reset() + * @see #getColorMatrix(ColorMatrix) * @see #setColorMatrix(ColorMatrix) + * @see ColorMatrix#reset() * * @throws ArrayIndexOutOfBoundsException if the specified array's * length is < 20 - * - * @hide */ - public void setColorMatrix(float[] array) { + public void setColorMatrixArray(@Nullable float[] array) { + // called '...Array' so that passing null isn't ambiguous + discardNativeInstance(); if (array == null) { mMatrix.reset(); } else { if (array.length < 20) { throw new ArrayIndexOutOfBoundsException(); } - mMatrix.set(array); } - update(); } - private void update() { - final float[] colorMatrix = mMatrix.getArray(); - destroyFilter(native_instance); - native_instance = nativeColorMatrixFilter(colorMatrix); + @Override + long createNativeInstance() { + return nativeColorMatrixFilter(mMatrix.getArray()); } private static native long nativeColorMatrixFilter(float[] array); diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index ad78430e2472..b0c145beb649 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -21,6 +21,8 @@ package android.graphics; +import android.annotation.ColorInt; + /** * A color filter that can be used to simulate simple lighting effects. * A <code>LightingColorFilter</code> is defined by two parameters, one @@ -37,7 +39,9 @@ package android.graphics; * The result is pinned to the <code>[0..255]</code> range for each channel. */ public class LightingColorFilter extends ColorFilter { + @ColorInt private int mMul; + @ColorInt private int mAdd; /** @@ -45,10 +49,9 @@ public class LightingColorFilter extends ColorFilter { * and then adds a second color. The alpha components of the mul and add * arguments are ignored. */ - public LightingColorFilter(int mul, int add) { + public LightingColorFilter(@ColorInt int mul, @ColorInt int add) { mMul = mul; mAdd = add; - update(); } /** @@ -56,9 +59,8 @@ public class LightingColorFilter extends ColorFilter { * color filter is applied. * * @see #setColorMultiply(int) - * - * @hide */ + @ColorInt public int getColorMultiply() { return mMul; } @@ -69,12 +71,12 @@ public class LightingColorFilter extends ColorFilter { * The alpha channel of this color is ignored. * * @see #getColorMultiply() - * - * @hide */ - public void setColorMultiply(int mul) { - mMul = mul; - update(); + public void setColorMultiply(@ColorInt int mul) { + if (mMul != mul) { + mMul = mul; + discardNativeInstance(); + } } /** @@ -82,9 +84,8 @@ public class LightingColorFilter extends ColorFilter { * when the color filter is applied. * * @see #setColorAdd(int) - * - * @hide */ + @ColorInt public int getColorAdd() { return mAdd; } @@ -95,17 +96,17 @@ public class LightingColorFilter extends ColorFilter { * The alpha channel of this color is ignored. * * @see #getColorAdd() - * - * @hide */ - public void setColorAdd(int add) { - mAdd = add; - update(); + public void setColorAdd(@ColorInt int add) { + if (mAdd != add) { + mAdd = add; + discardNativeInstance(); + } } - private void update() { - destroyFilter(native_instance); - native_instance = native_CreateLightingFilter(mMul, mAdd); + @Override + long createNativeInstance() { + return native_CreateLightingFilter(mMul, mAdd); } private static native long native_CreateLightingFilter(int mul, int add); diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 7ca4615434f5..5d6aa8a5f16d 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -42,7 +42,8 @@ import libcore.util.NativeAllocationRegistry; public class Paint { private long mNativePaint; - private long mNativeShader = 0; + private long mNativeShader; + private long mNativeColorFilter; // The approximate size of a native paint object. private static final long NATIVE_PAINT_SIZE = 98; @@ -584,6 +585,11 @@ public class Paint { mNativeShader = newNativeShader; nSetShader(mNativePaint, mNativeShader); } + long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance(); + if (newNativeColorFilter != mNativeColorFilter) { + mNativeColorFilter = newNativeColorFilter; + nSetColorFilter(mNativePaint, mNativeColorFilter); + } return mNativePaint; } @@ -1044,10 +1050,13 @@ public class Paint { * @return filter */ public ColorFilter setColorFilter(ColorFilter filter) { - long filterNative = 0; - if (filter != null) - filterNative = filter.native_instance; - nSetColorFilter(mNativePaint, filterNative); + // If mColorFilter changes, cached value of native shader aren't valid, since + // old shader's pointer may be reused by another shader allocation later + if (mColorFilter != filter) { + mNativeColorFilter = -1; + } + + // Defer setting the filter natively until getNativeInstance() is called mColorFilter = filter; return filter; } diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index 69d68910c8b5..ccc6eadc3df5 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; * color and a specific {@link PorterDuff Porter-Duff composite mode}. */ public class PorterDuffColorFilter extends ColorFilter { + @ColorInt private int mColor; private PorterDuff.Mode mMode; @@ -40,7 +41,6 @@ public class PorterDuffColorFilter extends ColorFilter { public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { mColor = color; mMode = mode; - update(); } /** @@ -49,9 +49,8 @@ public class PorterDuffColorFilter extends ColorFilter { * * @see Color * @see #setColor(int) - * - * @hide */ + @ColorInt public int getColor() { return mColor; } @@ -65,12 +64,12 @@ public class PorterDuffColorFilter extends ColorFilter { * @see Color * @see #getColor() * @see #getMode() - * - * @hide */ - public void setColor(int color) { - mColor = color; - update(); + public void setColor(@ColorInt int color) { + if (mColor != color) { + mColor = color; + discardNativeInstance(); + } } /** @@ -79,8 +78,6 @@ public class PorterDuffColorFilter extends ColorFilter { * * @see PorterDuff * @see #setMode(android.graphics.PorterDuff.Mode) - * - * @hide */ public PorterDuff.Mode getMode() { return mMode; @@ -93,17 +90,18 @@ public class PorterDuffColorFilter extends ColorFilter { * @see PorterDuff * @see #getMode() * @see #getColor() - * - * @hide */ public void setMode(@NonNull PorterDuff.Mode mode) { + if (mode == null) { + throw new IllegalArgumentException("mode must be non-null"); + } mMode = mode; - update(); + discardNativeInstance(); } - private void update() { - destroyFilter(native_instance); - native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt); + @Override + long createNativeInstance() { + return native_CreatePorterDuffFilter(mColor, mMode.nativeInt); } @Override @@ -115,10 +113,7 @@ public class PorterDuffColorFilter extends ColorFilter { return false; } final PorterDuffColorFilter other = (PorterDuffColorFilter) object; - if (mColor != other.mColor || mMode != other.mMode) { - return false; - } - return true; + return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt); } @Override diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index b584e0dd0417..8410ab2a1e02 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -106,8 +106,10 @@ public class Shader { } void discardNativeInstance() { - nativeSafeUnref(mNativeInstance); - mNativeInstance = 0; + if (mNativeInstance != 0) { + nativeSafeUnref(mNativeInstance); + mNativeInstance = 0; + } } /** @@ -120,7 +122,9 @@ public class Shader { @Override protected void finalize() throws Throwable { try { - nativeSafeUnref(mNativeInstance); + if (mNativeInstance != 0) { + nativeSafeUnref(mNativeInstance); + } mNativeInstance = -1; } finally { super.finalize(); diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 0722c1856372..c6c92714d1cc 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -218,6 +218,8 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback } /** + * Only call this method after bound is set on this drawable. + * * @return the mask path object used to clip the drawable */ public Path getIconMask() { diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 3a12419c8774..a1539b8f805a 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -333,7 +333,7 @@ public class VectorDrawable extends Drawable { // Color filters always override tint filters. final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter); final long colorFilterNativeInstance = colorFilter == null ? 0 : - colorFilter.native_instance; + colorFilter.getNativeInstance(); boolean canReuseCache = mVectorState.canReuseCache(); int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(), colorFilterNativeInstance, mTmpBounds, needMirroring(), diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h index d8afa35d32bf..a738ba4fe97e 100644 --- a/libs/hwui/FloatColor.h +++ b/libs/hwui/FloatColor.h @@ -38,13 +38,14 @@ struct FloatColor { } // "color" is a gamma-encoded sRGB color - // After calling this method, the color is stored as a linear color. The color - // is not pre-multiplied. - void setUnPreMultipliedSRGB(uint32_t color) { + // After calling this method, the color is stored as a un-premultiplied linear color + // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied + // gamma-encoded sRGB color + void setUnPreMultiplied(uint32_t color) { a = ((color >> 24) & 0xff) / 255.0f; - r = EOCF_sRGB(((color >> 16) & 0xff) / 255.0f); - g = EOCF_sRGB(((color >> 8) & 0xff) / 255.0f); - b = EOCF_sRGB(((color ) & 0xff) / 255.0f); + r = EOCF(((color >> 16) & 0xff) / 255.0f); + g = EOCF(((color >> 8) & 0xff) / 255.0f); + b = EOCF(((color ) & 0xff) / 255.0f); } bool isNotBlack() { diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 18bfcc2bbddf..dceb28518db3 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -189,9 +189,9 @@ void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount, uint8_t*& dst) const { float oppAmount = 1.0f - amount; float a = start.a * oppAmount + end.a * amount; - *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f); - *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f); - *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f); + *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f); + *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f); + *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f); *dst++ = uint8_t(a * 255.0f); } @@ -201,17 +201,14 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float a = start.a * oppAmount + end.a * amount; float* d = (float*) dst; #ifdef ANDROID_ENABLE_LINEAR_BLENDING + // We want to stay linear *d++ = a * (start.r * oppAmount + end.r * amount); *d++ = a * (start.g * oppAmount + end.g * amount); *d++ = a * (start.b * oppAmount + end.b * amount); #else - // What we're doing to the alpha channel here is technically incorrect - // but reproduces Android's old behavior when the alpha was pre-multiplied - // with gamma-encoded colors - a = EOCF_sRGB(a); - *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount); - *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount); - *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount); + *d++ = a * OECF(start.r * oppAmount + end.r * amount); + *d++ = a * OECF(start.g * oppAmount + end.g * amount); + *d++ = a * OECF(start.b * oppAmount + end.b * amount); #endif *d++ = a; dst += 4 * sizeof(float); @@ -232,10 +229,10 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, ChannelMixer mix = gMixers[mUseFloatTexture]; FloatColor start; - start.setUnPreMultipliedSRGB(colors[0]); + start.setUnPreMultiplied(colors[0]); FloatColor end; - end.setUnPreMultipliedSRGB(colors[1]); + end.setUnPreMultiplied(colors[1]); int currentPos = 1; float startPos = positions[0]; @@ -250,7 +247,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, currentPos++; - end.setUnPreMultipliedSRGB(colors[currentPos]); + end.setUnPreMultiplied(colors[currentPos]); distance = positions[currentPos] - startPos; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 40ab7788f218..38c23e4babe8 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -190,7 +190,7 @@ const char* gFS_Transfer_Functions = R"__SHADER__( // Dithering must be done in the quantization space // When we are writing to an sRGB framebuffer, we must do the following: // EOTF(OETF(color) + dither) -// The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0] +// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0] // TODO: Handle linear fp16 render targets const char* gFS_Gradient_Functions = R"__SHADER__( float triangleNoise(const highp vec2 n) { @@ -202,23 +202,26 @@ const char* gFS_Gradient_Functions = R"__SHADER__( )__SHADER__"; const char* gFS_Gradient_Preamble[2] = { // Linear framebuffer - "\nvec4 dither(const vec4 color) {\n" - " return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n" - "}\n" - "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n" - " vec4 c = mix(a, b, v);\n" - " c.a = EOTF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility - " return vec4(OETF_sRGB(c.rgb) * c.a, c.a);\n" - "}\n", + R"__SHADER__( + vec4 dither(const vec4 color) { + return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); + } + vec4 gradientMix(const vec4 a, const vec4 b, float v) { + vec4 c = mix(a, b, v); + return vec4(c.rgb * c.a, c.a); + } + )__SHADER__", // sRGB framebuffer - "\nvec4 dither(const vec4 color) {\n" - " vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n" - " return vec4(dithered * dithered, color.a);\n" - "}\n" - "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n" - " vec4 c = mix(a, b, v);\n" - " return vec4(c.rgb * c.a, c.a);\n" - "}\n" + R"__SHADER__( + vec4 dither(const vec4 color) { + vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); + return vec4(dithered * dithered, color.a); + } + vec4 gradientMixMix(const vec4 a, const vec4 b, float v) { + vec4 c = mix(a, b, v); + return vec4(c.rgb * c.a, c.a); + } + )__SHADER__", }; // Uses luminance coefficients from Rec.709 to choose the appropriate gamma @@ -272,19 +275,19 @@ const char* gFS_Main_FetchGradient[6] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, linear);\n", - " vec4 gradientColor = gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", + " vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", // Circular " vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n", - " vec4 gradientColor = gammaMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", + " vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", // Sweep " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n", " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" - " vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" + " vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" }; const char* gFS_Main_FetchBitmap = " vec4 bitmapColor = OETF(texture2D(bitmapSampler, outBitmapTexCoords));\n"; diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 760c10c6130e..4f7f9d7f9b9a 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -173,8 +173,8 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode outData->gradientSampler = 0; outData->gradientTexture = nullptr; - outData->startColor.setUnPreMultipliedSRGB(gradInfo.fColors[0]); - outData->endColor.setUnPreMultipliedSRGB(gradInfo.fColors[1]); + outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]); + outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]); } return true; diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp index 537b3eaa3ad5..ef4784b3d65b 100644 --- a/libs/hwui/VkLayer.cpp +++ b/libs/hwui/VkLayer.cpp @@ -29,7 +29,7 @@ void VkLayer::updateTexture() { SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType); surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info); surface->getCanvas()->clear(SK_ColorBLUE); - mImage = surface->makeImageSnapshot(SkBudgeted::kNo); + mImage = surface->makeImageSnapshot(); } void VkLayer::onVkContextDestroyed() { diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 62fd39516b85..c28aa5ec8711 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -1807,6 +1807,9 @@ public final class TvContract { * {@link #TYPE_S_DMB}, and * {@link #TYPE_T_DMB}. * + * <p>This value cannot be changed once it's set. Trying to modify it will make the update + * fail. + * * <p>This is a required field. * * <p>Type: TEXT diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk index e50d6fb693c9..148cd0d930ab 100644 --- a/packages/MtpDocumentsProvider/tests/Android.mk +++ b/packages/MtpDocumentsProvider/tests/Android.mk @@ -8,5 +8,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk index d1d0ee40ba01..3c02453c78a1 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.mk +++ b/packages/PrintSpooler/tests/outofprocess/Android.mk @@ -24,5 +24,6 @@ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java index 3fc999fb903a..f6f81682ad6f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java @@ -48,7 +48,7 @@ public class DashboardCategory implements Parcelable { /** * List of the category's children */ - public List<Tile> tiles = new ArrayList<Tile>(); + public List<Tile> tiles = new ArrayList<>(); public DashboardCategory() { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 457ce76d79ac..af247bdbb392 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -30,7 +30,6 @@ import android.os.Bundle; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -40,10 +39,8 @@ import android.widget.FrameLayout; import android.widget.Toolbar; import com.android.settingslib.R; -import com.android.settingslib.applications.InterestingConfigChanges; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; public class SettingsDrawerActivity extends Activity { @@ -63,15 +60,6 @@ public class SettingsDrawerActivity extends Activity { private FrameLayout mContentHeaderContainer; - // Remove below after new IA - @Deprecated - private static List<DashboardCategory> sDashboardCategories; - @Deprecated - private static HashMap<Pair<String, String>, Tile> sTileCache; - @Deprecated - private static InterestingConfigChanges sConfigTracker; - // Remove above after new IA - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -175,17 +163,6 @@ public class SettingsDrawerActivity extends Activity { getActionBar().setDisplayHomeAsUpEnabled(true); } - public List<DashboardCategory> getDashboardCategories() { - if (sDashboardCategories == null) { - sTileCache = new HashMap<>(); - sConfigTracker = new InterestingConfigChanges(); - // Apply initial current config. - sConfigTracker.applyNewConfig(getResources()); - sDashboardCategories = TileUtils.getCategories(this, sTileCache); - } - return sDashboardCategories; - } - protected void onCategoriesChanged() { final int N = mCategoryListeners.size(); for (int i = 0; i < N; i++) { diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk index 60d1c770d0de..7ace048324c3 100644 --- a/packages/SettingsLib/tests/integ/Android.mk +++ b/packages/SettingsLib/tests/integ/Android.mk @@ -25,6 +25,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common LOCAL_JACK_FLAGS := --multi-dex native LOCAL_PACKAGE_NAME := SettingsLibTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 91a4e792bbb8..1f1c18976edf 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -248,6 +248,9 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") private HandlerThread mHandlerThread; + @GuardedBy("mLock") + private Handler mHandler; + // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; @@ -300,10 +303,13 @@ public class SettingsProvider extends ContentProvider { mHandlerThread = new HandlerThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND); mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); mSettingsRegistry = new SettingsRegistry(); } - registerBroadcastReceivers(); - startWatchingUserRestrictionChanges(); + mHandler.post(() -> { + registerBroadcastReceivers(); + startWatchingUserRestrictionChanges(); + }); ServiceManager.addService("settings", new SettingsService(this)); return true; } diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk index acd552da6081..48b757c30cd1 100644 --- a/packages/Shell/tests/Android.mk +++ b/packages/Shell/tests/Android.mk @@ -16,6 +16,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ legacy-android-test \ LOCAL_PACKAGE_NAME := ShellTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_INSTRUMENTATION_FOR := Shell LOCAL_CERTIFICATE := platform diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml index 2b75c369c2e0..696e9b121564 100644 --- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml +++ b/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml @@ -17,6 +17,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" /> + <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" /> <item android:color="@android:color/transparent" /> -</selector>
\ No newline at end of file +</selector> diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml index f296076adb4c..6415ecb44c2e 100644 --- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml +++ b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml @@ -17,14 +17,15 @@ Copyright (C) 2014 The Android Open Source Project android:width="48.0dp" android:height="48.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0"> + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> <group android:scaleX="1.2" android:scaleY="1.2" android:pivotX="12.0" android:pivotY="12.0"> <path - android:fillColor="@color/qs_user_detail_icon_muted" + android:fillColor="#FFFFFFFF" android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/> </group> </vector> diff --git a/packages/SystemUI/res/layout/pip_menu_action.xml b/packages/SystemUI/res/layout/pip_menu_action.xml index 77efc9be5bc8..9150a000de00 100644 --- a/packages/SystemUI/res/layout/pip_menu_action.xml +++ b/packages/SystemUI/res/layout/pip_menu_action.xml @@ -18,4 +18,5 @@ android:layout_width="@dimen/pip_action_size" android:layout_height="@dimen/pip_action_size" android:padding="@dimen/pip_action_padding" - android:background="?android:selectableItemBackgroundBorderless" />
\ No newline at end of file + android:background="?android:selectableItemBackgroundBorderless" + android:forceHasOverlappingRendering="false" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml index c6837fa30925..44ced1736f65 100644 --- a/packages/SystemUI/res/layout/pip_menu_activity.xml +++ b/packages/SystemUI/res/layout/pip_menu_activity.xml @@ -23,7 +23,8 @@ <FrameLayout android:id="@+id/menu_container" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:forceHasOverlappingRendering="false"> <ImageView android:id="@+id/dismiss" diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml index 8d1f9e4131f9..9d1fb8fd4c6f 100644 --- a/packages/SystemUI/res/layout/qs_tile_label.xml +++ b/packages/SystemUI/res/layout/qs_tile_label.xml @@ -14,24 +14,39 @@ See the License for the specific language governing permissions and limitations under the License. --> -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:paddingTop="8dp"> + <LinearLayout + android:id="@+id/label_group" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="horizontal" - android:gravity="center_horizontal" - android:paddingTop="8dp" - android:paddingBottom="8dp"> - <TextView android:id="@+id/tile_label" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:orientation="horizontal"> + + <TextView + android:id="@+id/tile_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="?android:attr/textColorPrimary" - android:gravity="center_horizontal" - android:minLines="2" + android:clickable="false" + android:maxLines="2" android:padding="0dp" android:textAppearance="@style/TextAppearance.QS.TileLabel" - android:clickable="false" /> - <ImageView android:id="@+id/restricted_padlock" + android:textColor="?android:attr/textColorPrimary"/> + + <ImageView + android:id="@+id/expand_indicator" + android:layout_marginStart="4dp" + android:layout_width="12dp" + android:layout_height="match_parent" + android:src="@drawable/qs_dual_tile_caret" + android:tint="?android:attr/textColorPrimary" /> + + <ImageView android:id="@+id/restricted_padlock" android:layout_width="@dimen/qs_tile_text_size" android:layout_height="match_parent" android:paddingBottom="@dimen/qs_tile_text_size" @@ -39,4 +54,32 @@ android:layout_marginLeft="@dimen/restricted_padlock_pading" android:scaleType="centerInside" android:visibility="gone" /> -</LinearLayout> + </LinearLayout> + + <TextView + android:id="@+id/app_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignStart="@id/label_group" + android:layout_alignEnd="@id/label_group" + android:layout_below="@id/label_group" + android:clickable="false" + android:maxLines="1" + android:padding="0dp" + android:visibility="gone" + android:gravity="center" + android:textAppearance="@style/TextAppearance.QS.TileLabel" + android:textColor="?android:attr/textColorPrimary"/> + + <View + android:id="@+id/underline" + android:layout_width="30dp" + android:layout_height="1dp" + android:layout_marginTop="2dp" + android:layout_alignStart="@id/label_group" + android:layout_alignEnd="@id/label_group" + android:layout_below="@id/label_group" + android:alpha="?android:attr/disabledAlpha" + android:background="?android:attr/colorForeground"/> + +</RelativeLayout> diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index 8c6c7cfc8048..c7bfaef8bbe8 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -53,7 +53,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="@dimen/qs_detail_item_secondary_text_size" - android:textColor="@color/qs_user_detail_name" + android:textColor="?android:attr/textColorSecondary" android:gravity="center_horizontal" /> <ImageView android:id="@+id/restricted_padlock" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index cbe822f2205d..a549c73c6527 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1160,7 +1160,8 @@ public class KeyguardViewMediator extends SystemUI { if (mOccluded != isOccluded) { mOccluded = isOccluded; - mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate); + mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate + && mDeviceInteractive); adjustStatusBarLocked(); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 2f9c3fc3368a..9cb518cfe2e7 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -19,8 +19,8 @@ package com.android.systemui.pip.phone; import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS; import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER; import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS; -import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS; import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU; +import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -33,13 +33,11 @@ import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; import android.content.Intent; import android.content.pm.ParceledListSlice; -import android.content.res.Resources; import android.graphics.Color; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -84,6 +82,8 @@ public class PipMenuActivity extends Activity { private static final float MENU_BACKGROUND_ALPHA = 0.3f; private static final float DISMISS_BACKGROUND_ALPHA = 0.8f; + private static final float DISABLED_ACTION_ALPHA = 0.54f; + private boolean mMenuVisible; private final List<RemoteAction> mActions = new ArrayList<>(); private View mViewRoot; @@ -249,6 +249,7 @@ public class PipMenuActivity extends Activity { private void showMenu(Rect stackBounds, Rect movementBounds) { if (!mMenuVisible) { + setVisible(true); updateActionViews(stackBounds); if (mMenuContainerAnimator != null) { mMenuContainerAnimator.cancel(); @@ -268,7 +269,10 @@ public class PipMenuActivity extends Activity { mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener); mMenuContainerAnimator.start(); } else { + // If we are already visible, then just start the delayed dismiss and unregister any + // existing input consumers from the previous drag repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY); + notifyUnregisterInputConsumer(); } } @@ -292,9 +296,7 @@ public class PipMenuActivity extends Activity { if (animationFinishedRunnable != null) { animationFinishedRunnable.run(); } - if (getSystemService(AccessibilityManager.class).isEnabled()) { - finish(); - } + setVisible(false); } }); mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener); @@ -369,13 +371,18 @@ public class PipMenuActivity extends Activity { actionView.setImageDrawable(d); }, mHandler); actionView.setContentDescription(action.getContentDescription()); - actionView.setOnClickListener(v -> { - try { - action.getActionIntent().send(); - } catch (CanceledException e) { - Log.w(TAG, "Failed to send action", e); - } - }); + if (action.isEnabled()) { + actionView.setOnClickListener(v -> { + try { + action.getActionIntent().send(); + } catch (CanceledException e) { + Log.w(TAG, "Failed to send action", e); + } + }); + } else { + actionView.setAlpha(DISABLED_ACTION_ALPHA); + actionView.setEnabled(false); + } if (isLandscapePip && i > 0) { LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionView.getLayoutParams(); @@ -398,6 +405,7 @@ public class PipMenuActivity extends Activity { } private void updateDismissFraction(float fraction) { + setVisible(true); int alpha; if (mMenuVisible) { mMenuContainer.setAlpha(1-fraction); @@ -416,6 +424,12 @@ public class PipMenuActivity extends Activity { sendMessage(m, "Could not notify controller to register input consumer"); } + private void notifyUnregisterInputConsumer() { + Message m = Message.obtain(); + m.what = PipMenuActivityController.MESSAGE_UNREGISTER_INPUT_CONSUMER; + sendMessage(m, "Could not notify controller to unregister input consumer"); + } + private void notifyMenuVisibility(boolean visible) { mMenuVisible = visible; Message m = Message.obtain(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 7dc455bd0d2c..724f45347f5d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -63,6 +63,7 @@ public class PipMenuActivityController { public static final int MESSAGE_DISMISS_PIP = 103; public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104; public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105; + public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106; /** * A listener interface to receive notification on changes in PIP. @@ -135,6 +136,10 @@ public class PipMenuActivityController { mInputConsumerController.registerInputConsumer(); break; } + case MESSAGE_UNREGISTER_INPUT_CONSUMER: { + mInputConsumerController.unregisterInputConsumer(); + break; + } case MESSAGE_UPDATE_ACTIVITY_CALLBACK: { mToActivityMessenger = msg.replyTo; mStartActivityRequested = 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 c52fc3e87b0e..f70d5b41ac3e 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -504,8 +504,8 @@ public class PipTouchHandler { return false; } - try { - if (ENABLE_DISMISS_DRAG_TO_TARGET) { + if (ENABLE_DISMISS_DRAG_TO_TARGET) { + try { mHandler.removeCallbacks(mShowDismissAffordance); PointF vel = mTouchState.getVelocity(); final float velocity = PointF.length(vel.x, vel.y); @@ -520,9 +520,9 @@ public class PipTouchHandler { return true; } } + } finally { + mDismissViewController.destroyDismissTarget(); } - } finally { - mDismissViewController.destroyDismissTarget(); } if (touchState.isDragging()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java index 0629d66767d0..b0806429df28 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java @@ -35,19 +35,13 @@ public class CustomizeTileView extends QSTileView { protected void createLabel() { super.createLabel(); mLabelMinLines = mLabel.getMinLines(); - View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null); - mAppLabel = (TextView) view.findViewById(R.id.tile_label); + mAppLabel = findViewById(R.id.app_label); mAppLabel.setAlpha(.6f); - mAppLabel.setSingleLine(true); - addView(view); } public void setShowAppLabel(boolean showAppLabel) { mAppLabel.setVisibility(showAppLabel ? View.VISIBLE : View.GONE); mLabel.setSingleLine(showAppLabel); - if (!showAppLabel) { - mLabel.setMinLines(mLabelMinLines); - } } public void setAppLabel(CharSequence label) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index c0fb4d5e956c..d8e554254076 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -41,10 +41,10 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.qs.QS; -import com.android.systemui.qs.QSDetailClipper; import com.android.systemui.plugins.qs.QSTile; -import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; +import com.android.systemui.qs.QSDetailClipper; import com.android.systemui.qs.QSTileHost; +import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback; @@ -74,6 +74,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene private boolean mFinishedFetchingTiles = false; private int mX; private int mY; + private boolean mOpening; public QSCustomizer(Context context, AttributeSet attrs) { super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); @@ -140,6 +141,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mY = y; MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT); isShown = true; + mOpening = true; setTileSpecs(); setVisibility(View.VISIBLE); mClipper.animateCircularClip(x, y, true, mExpandAnimationListener); @@ -226,7 +228,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene } private final Callback mKeyguardCallback = () -> { - if (Dependency.get(KeyguardMonitor.class).isShowing()) { + if (!isAttachedToWindow()) return; + if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) { hide(0, 0); } }; @@ -237,11 +240,13 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene if (isShown) { setCustomizing(true); } + mOpening = false; mNotifQsContainer.setCustomizerAnimating(false); } @Override public void onAnimationCancel(Animator animation) { + mOpening = false; mNotifQsContainer.setCustomizerAnimating(false); } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 547bef72863f..2ac592ffe5bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -165,6 +165,7 @@ public class TileQueryHelper { } TileInfo info = new TileInfo(); info.state = state; + info.state.dualTarget = false; // No dual targets in edit. info.state.expandedAccessibilityClassName = Button.class.getName(); info.spec = spec; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java index 5ac78919f006..948954c2bd99 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java @@ -369,7 +369,6 @@ public abstract class QSTileImpl<TState extends State> implements QSTile { Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard( intent, 0); } else { - mAnnounceNextStateChange = true; handleClick(); } } else if (msg.what == SECONDARY_CLICK) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java index 2c04e82bad72..d2ae6e9f5354 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java @@ -36,11 +36,12 @@ import libcore.util.Objects; /** View that represents a standard quick settings tile. **/ public class QSTileView extends QSTileBaseView { - private final View mDivider; + private View mDivider; protected TextView mLabel; private ImageView mPadLock; private int mState; private ViewGroup mLabelContainer; + private View mExpandIndicator; public QSTileView(Context context, QSIconView icon) { this(context, icon, false); @@ -54,8 +55,6 @@ public class QSTileView extends QSTileBaseView { setClickable(true); setId(View.generateViewId()); - mDivider = LayoutInflater.from(context).inflate(R.layout.divider, this, false); - addView(mDivider); createLabel(); setOrientation(VERTICAL); setGravity(Gravity.CENTER); @@ -81,8 +80,10 @@ public class QSTileView extends QSTileBaseView { .inflate(R.layout.qs_tile_label, this, false); mLabelContainer.setClipChildren(false); mLabelContainer.setClipToPadding(false); - mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label); - mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock); + mLabel = mLabelContainer.findViewById(R.id.tile_label); + mPadLock = mLabelContainer.findViewById(R.id.restricted_padlock); + mDivider = mLabelContainer.findViewById(R.id.underline); + mExpandIndicator = mLabelContainer.findViewById(R.id.expand_indicator); addView(mLabelContainer); } @@ -101,6 +102,7 @@ public class QSTileView extends QSTileBaseView { mLabel.setText(state.label); } mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE); + mExpandIndicator.setVisibility(state.dualTarget ? View.VISIBLE : View.GONE); if (state.dualTarget != mLabelContainer.isClickable()) { mLabelContainer.setClickable(state.dualTarget); mLabelContainer.setLongClickable(state.dualTarget); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 47468aeaeb97..ac24e2e715df 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -67,6 +67,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArraySet; +import android.util.LauncherIcons; import android.util.Log; import android.util.MutableBoolean; import android.view.Display; @@ -142,6 +143,7 @@ public class SystemServicesProxy { int mDummyThumbnailHeight; Paint mBgProtectionPaint; Canvas mBgProtectionCanvas; + LauncherIcons mLauncherIcons; private final Handler mHandler = new H(); @@ -299,6 +301,7 @@ public class SystemServicesProxy { Collections.addAll(sRecentsBlacklist, res.getStringArray(R.array.recents_blacklist_array)); } + mLauncherIcons = new LauncherIcons(context); } /** @@ -834,7 +837,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = info.loadIcon(mPm); + Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm)); return getBadgedIcon(icon, userId); } @@ -850,7 +853,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = appInfo.loadIcon(mPm); + Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm)); return getBadgedIcon(icon, userId); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java index af464c6d138f..5db5498e9bb6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java @@ -136,12 +136,7 @@ public class NotificationInfo extends LinearLayout implements GutsContent { if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) { channelNameText = mContext.getString(R.string.notification_header_default_channel); } else { - if (info != null && channel.getNameResId() != 0) { - channelNameText = pm.getText(pkg, channel.getNameResId(), info); - } - if (channel.getName() != null) { - channelNameText = channel.getName(); - } + channelNameText = channel.getName(); } ((TextView) findViewById(R.id.pkgname)).setText(appName); ((TextView) findViewById(R.id.channel_name)).setText(channelNameText); @@ -154,12 +149,7 @@ public class NotificationInfo extends LinearLayout implements GutsContent { iNotificationManager.getNotificationChannelGroupForPackage( channel.getGroup(), pkg, appUid); if (notificationChannelGroup != null) { - if (info != null && notificationChannelGroup.getNameResId() != 0) { - groupName = pm.getText(pkg, notificationChannelGroup.getNameResId(), info); - } - if (notificationChannelGroup.getName() != null) { - groupName = notificationChannelGroup.getName(); - } + groupName = notificationChannelGroup.getName(); } } catch (RemoteException e) { Log.e(TAG, e.toString()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 820638cb3c2d..c30bb9a2e6e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -74,7 +74,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener if (mUserListener == null) { return false; } - return mUserListener.getUserCount() > 1; + return mUserListener.getUserCount() != 0; } public void setUserSwitcherController(UserSwitcherController userSwitcherController) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java index a87b50a4a8df..d6c080ad1f44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java @@ -129,6 +129,7 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback public void notifyKeyguardDoneFading() { mKeyguardFadingAway = false; + mKeyguardGoingAway = false; notifyKeyguardChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 5df3beb471b5..cd85a760159b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -38,19 +38,19 @@ public class NotificationChannels extends SystemUI { nm.createNotificationChannels(Arrays.asList( new NotificationChannel( ALERTS, - R.string.notification_channel_alerts, + context.getString(R.string.notification_channel_alerts), NotificationManager.IMPORTANCE_HIGH), new NotificationChannel( SCREENSHOTS, - R.string.notification_channel_screenshot, + context.getString(R.string.notification_channel_screenshot), NotificationManager.IMPORTANCE_LOW), new NotificationChannel( GENERAL, - R.string.notification_channel_general, + context.getString(R.string.notification_channel_general), NotificationManager.IMPORTANCE_MIN), new NotificationChannel( STORAGE, - R.string.notification_channel_storage, + context.getString(R.string.notification_channel_storage), isTv(context) ? NotificationManager.IMPORTANCE_DEFAULT : NotificationManager.IMPORTANCE_LOW) diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 576299fe0057..ddd8d7b3002f 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -26,6 +26,7 @@ LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/.. LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors LOCAL_PACKAGE_NAME := SystemUITests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_SRC_FILES := $(call all-java-files-under, src) \ $(call all-Iaidl-files-under, src) \ @@ -46,7 +47,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \ LOCAL_STATIC_JAVA_LIBRARIES := \ metrics-helper-lib \ android-support-test \ - mockito-updated-target-minus-junit4 \ + mockito-target-minus-junit4 \ SystemUI-proto \ SystemUI-tags \ legacy-android-test \ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java index 5b9270d4e4ed..726300f79fc1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java @@ -161,27 +161,6 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBindNotification_SetsGroupName_resId() throws Exception { - when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME), - eq(R.string.legacy_vpn_name), anyObject())).thenReturn( - getContext().getString(R.string.legacy_vpn_name)); - mNotificationChannel.setGroup("test_group_id"); - final NotificationChannelGroup notificationChannelGroup = - new NotificationChannelGroup("test_group_id", R.string.legacy_vpn_name); - when(mMockINotificationManager.getNotificationChannelGroupForPackage( - eq("test_group_id"), eq(TEST_PACKAGE_NAME), anyInt())) - .thenReturn(notificationChannelGroup); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - mMockStatusBarNotification, mNotificationChannel, null, null, null); - final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name); - assertEquals(View.VISIBLE, groupNameView.getVisibility()); - assertEquals(mContext.getString(R.string.legacy_vpn_name), groupNameView.getText()); - final TextView groupDividerView = - (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider); - assertEquals(View.VISIBLE, groupDividerView.getVisibility()); - } - - @Test public void testBindNotification_SetsTextChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, mMockStatusBarNotification, mNotificationChannel, null, null, null); @@ -190,21 +169,6 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBindNotification_SetsTextChannelName_resId() throws Exception { - when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME), - eq(R.string.notification_menu_accessibility), anyObject())).thenReturn( - getContext().getString(R.string.notification_menu_accessibility)); - NotificationChannel notificationChannelResId = new NotificationChannel( - TEST_CHANNEL, R.string.notification_menu_accessibility, - NotificationManager.IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - mMockStatusBarNotification, notificationChannelResId, null, null, null); - final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); - assertEquals(getContext().getString(R.string.notification_menu_accessibility), - textView.getText()); - } - - @Test public void testBindNotification_SetsOnClickListenerForSettings() throws Exception { final CountDownLatch latch = new CountDownLatch(1); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 3800f297a8cc..8a3b9af0ce08 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -56,6 +56,12 @@ message MetricsEvent { // Type for APP_TRANSITION event: The transition brought an already existing activity to the // front. TYPE_TRANSITION_HOT_LAUNCH = 9; + + // The action was successful + TYPE_SUCCESS = 10; + + // The action failed + TYPE_FAILURE = 11; } // Known visual elements: views or controls. @@ -1180,7 +1186,7 @@ message MetricsEvent { // OS: 6.0 BRIGHTNESS_DIALOG = 220; - // OPEN: Settings > Apps > Configure Apps > Draw over other apps + // OPEN: Settings > Apps > Configure Apps > Display over other apps // CATEGORY: SETTINGS // OS: 6.0 SYSTEM_ALERT_WINDOW_APPS = 221; @@ -3227,7 +3233,7 @@ message MetricsEvent { // ACTION: Allow "Draw over other apps" for an app APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770; - // ACTION: Deny "Draw over other apps" for an app + // ACTION: Deny "Display over other apps" for an app APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771; // ACTION: Allow "VR helper services" for an app @@ -3608,6 +3614,169 @@ message MetricsEvent { // CATEGORY: SETTINGS SETTINGS_LOCK_SCREEN_PREFERENCES = 882; + // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883; + + // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS + // PACKAGE: The package name of the app that was granted the permission + ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884; + + // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885; + + // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886; + + // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887; + + // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW + // PACKAGE: The package name of the app that was granted the permission + ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888; + + // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889; + + // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890; + + // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891; + + // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS + // PACKAGE: The package name of the app that was granted the permission + ACTION_APPOP_GRANT_WRITE_SETTINGS = 892; + + // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_DENIED_WRITE_SETTINGS = 893; + + // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894; + + // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895; + + // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES + // PACKAGE: The package name of the app that was granted the permission + ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896; + + // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied + // PACKAGE: The package name of the app requesting the permission + ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897; + + // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898; + + // ACTION: Phase 1 of instant application resolution occurred + // OS: O + ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE = 899; + + // ACTION: Phase 2 of instant application resolution occurred + // OS: O + ACTION_INSTANT_APP_RESOLUTION_PHASE_TWO = 900; + + // FIELD: The amount of time for an ephemeral resolution phase; in milliseconds + // OS: O + FIELD_INSTANT_APP_RESOLUTION_DELAY_MS = 901; + + // FIELD: The status of an ephemeral resolution phase + // Value 0: success + // Value 1: no full hash match + // OS: O + FIELD_INSTANT_APP_RESOLUTION_STATUS = 902; + + // FIELD - A token to identify all events that are part of the same instant application launch + // OS: O + FIELD_INSTANT_APP_LAUNCH_TOKEN = 903; + + // FIELD - The name of the package responsible for launching the activity + // OS: O + APP_TRANSITION_CALLING_PACKAGE_NAME = 904; + + // FIELD - Whether or not the launched activity is part of an instant application + // OS: O + APP_TRANSITION_IS_EPHEMERAL = 905; + + // An autofill session was started + // Package: Package of app that is autofilled + AUTOFILL_SESSION_STARTED = 906; + + // An autofill request was processed by a service + // Type TYPE_SUCCESS: The request succeeded + // Type TYPE_FAILURE: The request failed + // Package: Package of app that is autofilled + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case) + AUTOFILL_REQUEST = 907; + + // Tag of a field for a package of an autofill service + FIELD_AUTOFILL_SERVICE = 908; + + // Tag of a field for the number of datasets + FIELD_AUTOFILL_NUM_DATASETS = 909; + + // An autofill dataset selection UI was shown + // Type TYPE_DISMISS: UI was explicityly canceled by the user + // Type TYPE_CLOSE: UI was destroyed without influence of the user + // Type TYPE_ACTION: dataset was selected + // Type TYPE_DETAIL: authentication was selected + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text + // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown + AUTOFILL_FILL_UI = 910; + + // Tag of a field for the length of the filter text + FIELD_AUTOFILL_FILTERTEXT_LEN = 911; + + // An autofill authentification succeeded + // Package: Package of app that was autofilled + AUTOFILL_AUTHENTICATED = 912; + + // An activity was autofilled and all values could be applied + // Package: Package of app that is autofilled + // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled + // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled + AUTOFILL_DATASET_APPLIED = 913; + + // Tag of a field for the number values to be filled in + FIELD_AUTOFILL_NUM_VALUES = 914; + + // Tag of a field for the number of views that were filled + FIELD_AUTOFILL_NUM_VIEWS_FILLED = 915; + + // An autofill save UI was shown + // Type TYPE_DISMISS: UI was explicityly canceled by the user + // Type TYPE_CLOSE: UI was destroyed without influence of the user + // Type TYPE_ACTION: data was saved + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_NUM_ID: The number of ids that are saved + AUTOFILL_SAVE_UI = 916; + + // Tag of a field for the number of saveable ids + FIELD_AUTOFILL_NUM_IDS = 917; + + // ACTION: An autofill service was reqiested to save data + // Type TYPE_SUCCESS: The request succeeded + // Type TYPE_FAILURE: The request failed + // Package: Package of app that was autofilled + // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request + AUTOFILL_DATA_SAVE_REQUEST = 918; + + // An auto-fill session was finished + // Package: Package of app that was autofilled + AUTOFILL_SESSION_FINISHED = 919; + // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index af1193d7edea..c7ba1ff60a1e 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -28,6 +28,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.graphics.Rect; @@ -53,6 +54,7 @@ import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -316,13 +318,27 @@ public final class AutofillManagerService extends SystemService { @Override public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback, AutofillId autofillId, Rect bounds, AutofillValue value, int userId, - boolean hasCallback, int flags) { + boolean hasCallback, int flags, String packageName) { // TODO(b/33197203): make sure it's called by resumed / focused activity + activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); + appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); + autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); + bounds = Preconditions.checkNotNull(bounds, "bounds"); + packageName = Preconditions.checkNotNull(packageName, "packageName"); + + Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); + + try { + mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException(packageName + " is not a valid package", e); + } + synchronized (mLock) { final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); service.startSessionLocked(activityToken, windowToken, appCallback, - autofillId, bounds, value, hasCallback, flags); + autofillId, bounds, value, hasCallback, flags, packageName); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 3e5ad82d0129..df76009db008 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -28,6 +28,7 @@ import static com.android.server.autofill.Helper.DEBUG; import static com.android.server.autofill.Helper.VERBOSE; import static com.android.server.autofill.Helper.findValue; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -43,6 +44,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.graphics.Rect; +import android.metrics.LogMaker; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -67,7 +69,11 @@ import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; +import android.view.autofill.AutofillManager.AutofillCallback; + import com.android.internal.annotations.GuardedBy; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.HandlerCaller; import com.android.internal.os.IResultReceiver; import com.android.server.autofill.ui.AutoFillUI; @@ -92,6 +98,7 @@ final class AutofillManagerServiceImpl { private final Context mContext; private final Object mLock; private final AutoFillUI mUi; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); private RemoteCallbackList<IAutoFillManagerClient> mClients; private AutofillServiceInfo mInfo; @@ -228,9 +235,8 @@ final class AutofillManagerServiceImpl { if (!hasService()) { final int sessionCount = mSessions.size(); for (int i = sessionCount - 1; i >= 0; i--) { - Session session = mSessions.valueAt(i); - session.destroyLocked(); - mSessions.removeAt(i); + final Session session = mSessions.valueAt(i); + session.removeSelfLocked(); } } sendStateToClients(); @@ -284,9 +290,10 @@ final class AutofillManagerServiceImpl { } } - void startSessionLocked(IBinder activityToken, IBinder windowToken, IBinder appCallbackToken, - AutofillId autofillId, Rect bounds, AutofillValue value, boolean hasCallback, - int flags) { + void startSessionLocked(@NonNull IBinder activityToken, @Nullable IBinder windowToken, + @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect bounds, + @Nullable AutofillValue value, boolean hasCallback, int flags, + @NonNull String packageName) { if (!hasService()) { return; } @@ -305,7 +312,7 @@ final class AutofillManagerServiceImpl { } final Session newSession = createSessionByTokenLocked(activityToken, - windowToken, appCallbackToken, hasCallback, flags); + windowToken, appCallbackToken, hasCallback, flags, packageName); newSession.updateLocked(autofillId, bounds, value, FLAG_START_SESSION); } @@ -320,7 +327,13 @@ final class AutofillManagerServiceImpl { return; } - session.showSaveLocked(); + final boolean finished = session.showSaveLocked(); + if (DEBUG) { + Log.d(TAG, "finishSessionLocked(): session finished on save? " + finished); + } + if (finished) { + session.removeSelf(); + } } void cancelSessionLocked(IBinder activityToken) { @@ -333,14 +346,14 @@ final class AutofillManagerServiceImpl { Slog.w(TAG, "cancelSessionLocked(): no session for " + activityToken); return; } - - session.destroyLocked(); + session.removeSelfLocked(); } - private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken, - IBinder appCallbackToken, boolean hasCallback, int flags) { + private Session createSessionByTokenLocked(@NonNull IBinder activityToken, + @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback, + int flags, @NonNull String packageName) { final Session newSession = new Session(mContext, activityToken, - windowToken, appCallbackToken, hasCallback, flags); + windowToken, appCallbackToken, hasCallback, flags, packageName); mSessions.put(activityToken, newSession); /* @@ -351,7 +364,6 @@ final class AutofillManagerServiceImpl { * - display disclosure if needed */ try { - // TODO(b/33197203): add MetricsLogger call final Bundle receiverExtras = new Bundle(); receiverExtras.putBinder(EXTRA_ACTIVITY_TOKEN, activityToken); final long identity = Binder.clearCallingIdentity(); @@ -371,7 +383,6 @@ final class AutofillManagerServiceImpl { void updateSessionLocked(IBinder activityToken, AutofillId autofillId, Rect bounds, AutofillValue value, int flags) { - // TODO(b/33197203): add MetricsLogger call final Session session = mSessions.get(activityToken); if (session == null) { if (VERBOSE) { @@ -595,6 +606,9 @@ final class AutofillManagerServiceImpl { private final IBinder mActivityToken; private final IBinder mWindowToken; + /** Package name of the app that is auto-filled */ + @NonNull private final String mPackageName; + @GuardedBy("mLock") private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>(); @@ -634,15 +648,16 @@ final class AutofillManagerServiceImpl { * Flags used to start the session. */ private int mFlags; - - private Session(Context context, IBinder activityToken, IBinder windowToken, - IBinder client, boolean hasCallback, int flags) { + private Session(@NonNull Context context, @NonNull IBinder activityToken, + @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback, + int flags, @NonNull String packageName) { mRemoteFillService = new RemoteFillService(context, mInfo.getServiceInfo().getComponentName(), mUserId, this); mActivityToken = activityToken; mWindowToken = windowToken; mHasCallback = hasCallback; mFlags = flags; + mPackageName = packageName; mClient = IAutoFillManagerClient.Stub.asInterface(client); try { @@ -656,41 +671,82 @@ final class AutofillManagerServiceImpl { } catch (RemoteException e) { Slog.w(TAG, "linkToDeath() on mClient failed: " + e); } + + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_STARTED, mPackageName); } // FillServiceCallbacks @Override - public void onFillRequestSuccess(FillResponse response) { - // TODO(b/33197203): add MetricsLogger call + public void onFillRequestSuccess(@Nullable FillResponse response, + @NonNull String servicePackageName) { if (response == null) { + // Nothing to be done, but need to notify client. + notifyUnavailableToClient(); removeSelf(); return; } + + if ((response.getDatasets() == null || response.getDatasets().isEmpty()) + && response.getAuthentication() == null) { + // Response is "empty" from an UI point of view, need to notify client. + notifyUnavailableToClient(); + } synchronized (mLock) { processResponseLocked(response); } + + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, + response.getDatasets() == null ? 0 : response.getDatasets().size()) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); } // FillServiceCallbacks @Override - public void onFillRequestFailure(CharSequence message) { - // TODO(b/33197203): add MetricsLogger call + public void onFillRequestFailure(@Nullable CharSequence message, + @NonNull String servicePackageName) { + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_FAILURE) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + getUiForShowing().showError(message); removeSelf(); } // FillServiceCallbacks @Override - public void onSaveRequestSuccess() { - // TODO(b/33197203): add MetricsLogger call + public void onSaveRequestSuccess(@NonNull String servicePackageName) { + LogMaker log = (new LogMaker( + MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_SUCCESS) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + // Nothing left to do... removeSelf(); } // FillServiceCallbacks @Override - public void onSaveRequestFailure(CharSequence message) { - // TODO(b/33197203): add MetricsLogger call + public void onSaveRequestFailure(@Nullable CharSequence message, + @NonNull String servicePackageName) { + LogMaker log = (new LogMaker( + MetricsProto.MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST)) + .setType(MetricsProto.MetricsEvent.TYPE_FAILURE) + .setPackageName(mPackageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_SERVICE, + servicePackageName); + mMetricsLogger.write(log); + getUiForShowing().showError(message); removeSelf(); } @@ -702,9 +758,7 @@ final class AutofillManagerServiceImpl { synchronized (mLock) { fillInIntent = createAuthFillInIntent(mStructure); } - mHandlerCaller.getHandler().post(() -> { - startAuthentication(intent, fillInIntent); - }); + mHandlerCaller.getHandler().post(() -> startAuthentication(intent, fillInIntent)); } // FillServiceCallbacks @@ -724,8 +778,7 @@ final class AutofillManagerServiceImpl { Binder.restoreCallingIdentity(identity); } synchronized (mLock) { - destroyLocked(); - mSessions.remove(this); + removeSelfLocked(); } } @@ -738,9 +791,7 @@ final class AutofillManagerServiceImpl { // AutoFillUiCallback @Override public void fill(Dataset dataset) { - mHandlerCaller.getHandler().post(() -> { - autoFill(dataset); - }); + mHandlerCaller.getHandler().post(() -> autoFill(dataset)); } // AutoFillUiCallback @@ -753,17 +804,13 @@ final class AutofillManagerServiceImpl { // AutoFillUiCallback @Override public void cancelSave() { - mHandlerCaller.getHandler().post(() -> { - removeSelf(); - }); + mHandlerCaller.getHandler().post(() -> removeSelf()); } // AutoFillUiCallback @Override public void onEvent(AutofillId id, int event) { - mHandlerCaller.getHandler().post(() -> { - notifyChangeToClient(id, event); - }); + mHandlerCaller.getHandler().post(() -> notifyChangeToClient(id, event)); } public void setAuthenticationResultLocked(Bundle data) { @@ -773,6 +820,9 @@ final class AutofillManagerServiceImpl { Parcelable result = data.getParcelable( AutofillManager.EXTRA_AUTHENTICATION_RESULT); if (result instanceof FillResponse) { + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_AUTHENTICATED, + mPackageName); + mCurrentResponse = (FillResponse) result; processResponseLocked(mCurrentResponse); } else if (result instanceof Dataset) { @@ -790,12 +840,14 @@ final class AutofillManagerServiceImpl { } /** - * Show the save UI, when session can be saved. + * Shows the save UI, when session can be saved. + * + * @return {@code true} if session is done, or {@code false} if it's pending user action. */ - public void showSaveLocked() { + public boolean showSaveLocked() { if (mStructure == null) { Slog.wtf(TAG, "showSaveLocked(): no mStructure"); - return; + return true; } if (mCurrentResponse == null) { // Happens when the activity / session was finished before the service replied, or @@ -803,7 +855,7 @@ final class AutofillManagerServiceImpl { if (DEBUG) { Slog.d(TAG, "showSaveLocked(): no mCurrentResponse"); } - return; + return true; } final SaveInfo saveInfo = mCurrentResponse.getSaveInfo(); if (DEBUG) { @@ -819,13 +871,13 @@ final class AutofillManagerServiceImpl { */ if (saveInfo == null) { - return; + return true; } final AutofillId[] requiredIds = saveInfo.getRequiredIds(); if (requiredIds == null || requiredIds.length == 0) { Slog.w(TAG, "showSaveLocked(): no required ids on saveInfo"); - return; + return true; } boolean allRequiredAreNotEmpty = true; @@ -894,8 +946,8 @@ final class AutofillManagerServiceImpl { if (atLeastOneChanged) { getUiForShowing().showSaveUi( mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()), - saveInfo); - return; + saveInfo, mPackageName); + return false; } } // Nothing changed... @@ -904,7 +956,7 @@ final class AutofillManagerServiceImpl { + "allRequiredAreNotNull=" + allRequiredAreNotEmpty + ", atLeastOneChanged=" + atLeastOneChanged); } - removeSelf(); + return true; } /** @@ -946,7 +998,7 @@ final class AutofillManagerServiceImpl { mStructure.dump(); } - mRemoteFillService.onSaveRequest(mStructure, extras); + mRemoteFillService.onSaveRequest(mStructure, extras, () -> removeSelf()); } void updateLocked(AutofillId id, Rect bounds, AutofillValue value, int flags) { @@ -1034,7 +1086,7 @@ final class AutofillManagerServiceImpl { filterText = value.getTextValue().toString(); } - getUiForShowing().showFillUi(filledId, response, bounds, filterText); + getUiForShowing().showFillUi(filledId, response, bounds, filterText, mPackageName); } private void notifyChangeToClient(AutofillId id, int event) { @@ -1046,17 +1098,24 @@ final class AutofillManagerServiceImpl { } } + private void notifyUnavailableToClient() { + if (mCurrentViewState == null) { + // TODO(b/33197203): temporary sanity check; should never happen + Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null"); + return; + } + notifyChangeToClient(mCurrentViewState.mId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); + } + private void processResponseLocked(FillResponse response) { if (DEBUG) { Slog.d(TAG, "processResponseLocked(auth=" + response.getAuthentication() + "):" + response); } - // TODO(b/33197203): add MetricsLogger calls - if (mCurrentViewState == null) { // TODO(b/33197203): temporary sanity check; should never happen - Slog.w(TAG, "processResponseLocked(): mCurrentResponse is null"); + Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null"); return; } @@ -1188,17 +1247,23 @@ final class AutofillManagerServiceImpl { private void destroyLocked() { mRemoteFillService.destroy(); mUi.setCallback(null, null); + + mMetricsLogger.action(MetricsProto.MetricsEvent.AUTOFILL_SESSION_FINISHED, + mPackageName); } - private void removeSelf() { - if (VERBOSE) { - Slog.v(TAG, "removeSelf()"); + void removeSelf() { + synchronized (mLock) { + removeSelfLocked(); } + } - synchronized (mLock) { - destroyLocked(); - mSessions.remove(mActivityToken); + private void removeSelfLocked() { + if (VERBOSE) { + Slog.v(TAG, "removeSelfLocked()"); } + destroyLocked(); + mSessions.remove(mActivityToken); } } } diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index b1cc89b5de44..d1c8b4f84a91 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -16,6 +16,8 @@ package com.android.server.autofill; +import static com.android.server.autofill.Helper.DEBUG; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.assist.AssistStructure; @@ -38,8 +40,10 @@ import android.service.autofill.IFillCallback; import android.service.autofill.ISaveCallback; import android.text.format.DateUtils; import android.util.Slog; + import com.android.internal.os.HandlerCaller; import com.android.server.FgThread; +import com.android.server.autofill.AutofillManagerServiceImpl.Session; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -55,8 +59,6 @@ import java.lang.ref.WeakReference; final class RemoteFillService implements DeathRecipient { private static final String LOG_TAG = "RemoteFillService"; - private static final boolean DEBUG = Helper.DEBUG; - // How long after the last interaction with the service we would unbind private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; @@ -87,10 +89,10 @@ final class RemoteFillService implements DeathRecipient { private PendingRequest mPendingRequest; public interface FillServiceCallbacks { - void onFillRequestSuccess(FillResponse response); - void onFillRequestFailure(CharSequence message); - void onSaveRequestSuccess(); - void onSaveRequestFailure(CharSequence message); + void onFillRequestSuccess(@Nullable FillResponse response, @NonNull String servicePackageName); + void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); + void onSaveRequestSuccess(@NonNull String servicePackageName); + void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); void onServiceDied(RemoteFillService service); void onDisableSelf(); } @@ -139,9 +141,10 @@ final class RemoteFillService implements DeathRecipient { mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); } - public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras) { + public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras, + @Nullable Runnable finalizer) { cancelScheduledUnbind(); - final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this); + final PendingSaveRequest request = new PendingSaveRequest(structure, extras, this, finalizer); mHandler.obtainMessageO(MyHandler.MSG_ON_PENDING_REQUEST, request).sendToTarget(); } @@ -262,7 +265,7 @@ final class RemoteFillService implements DeathRecipient { FillResponse response) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestSuccess(response); + mCallbacks.onFillRequestSuccess(response, mComponentName.getPackageName()); } }); } @@ -271,7 +274,7 @@ final class RemoteFillService implements DeathRecipient { CharSequence message) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onFillRequestFailure(message); + mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName()); } }); } @@ -279,7 +282,7 @@ final class RemoteFillService implements DeathRecipient { private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onSaveRequestSuccess(); + mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName()); } }); } @@ -288,7 +291,7 @@ final class RemoteFillService implements DeathRecipient { CharSequence message) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onSaveRequestFailure(message); + mCallbacks.onSaveRequestFailure(message, mComponentName.getPackageName()); } }); } @@ -414,8 +417,8 @@ final class RemoteFillService implements DeathRecipient { private static final class PendingFillRequest extends PendingRequest { private final Object mLock = new Object(); private final WeakReference<RemoteFillService> mWeakService; - private AssistStructure mStructure; - private Bundle mExtras; + private final AssistStructure mStructure; + private final Bundle mExtras; private final IFillCallback mCallback; private ICancellationSignal mCancellation; private boolean mCancelled; @@ -473,10 +476,6 @@ final class RemoteFillService implements DeathRecipient { try { remoteService.mAutoFillService.onFillRequest(mStructure, mExtras, mCallback, mFlags); - synchronized (mLock) { - mStructure = null; - mExtras = null; - } } catch (RemoteException e) { Slog.e(LOG_TAG, "Error calling on fill request", e); cancel(); @@ -506,17 +505,18 @@ final class RemoteFillService implements DeathRecipient { } private static final class PendingSaveRequest extends PendingRequest { - private final Object mLock = new Object(); private final WeakReference<RemoteFillService> mWeakService; - private AssistStructure mStructure; - private Bundle mExtras; + private final AssistStructure mStructure; + private final Bundle mExtras; private final ISaveCallback mCallback; + private final Runnable mFinalizer; - public PendingSaveRequest(@NonNull AssistStructure structure, - @Nullable Bundle extras, @NonNull RemoteFillService service) { + public PendingSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle extras, + @NonNull RemoteFillService service, @Nullable Runnable finalizer) { mStructure = structure; mExtras = extras; mWeakService = new WeakReference<>(service); + mFinalizer = finalizer; mCallback = new ISaveCallback.Stub() { @Override public void onSuccess() { @@ -540,19 +540,17 @@ final class RemoteFillService implements DeathRecipient { @Override public void run() { - RemoteFillService service = mWeakService.get(); + final RemoteFillService service = mWeakService.get(); if (service != null) { try { - service.mAutoFillService.onSaveRequest(mStructure, - mExtras, mCallback); - synchronized (mLock) { - mStructure = null; - mExtras = null; - } + service.mAutoFillService.onSaveRequest(mStructure, mExtras, mCallback); } catch (RemoteException e) { Slog.e(LOG_TAG, "Error calling on save request", e); } } + if (mFinalizer != null) { + mFinalizer.run(); + } } @Override diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index c7e59a39aeef..776fa1e58db8 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.IntentSender; import android.graphics.Rect; +import android.metrics.LogMaker; import android.os.Handler; import android.os.IBinder; import android.service.autofill.Dataset; @@ -34,6 +35,8 @@ import android.util.Slog; import android.view.autofill.AutofillId; import android.widget.Toast; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.server.UiThread; import java.io.PrintWriter; @@ -60,6 +63,7 @@ public final class AutoFillUI { private @Nullable IBinder mWindowToken; private int mSaveTimeoutMs = (int) (5 * DateUtils.SECOND_IN_MILLIS); + private final MetricsLogger mMetricsLogger = new MetricsLogger(); public interface AutoFillUiCallback { void authenticate(@NonNull IntentSender intent); @@ -152,9 +156,17 @@ public final class AutoFillUI { * @param response the current fill response * @param anchorBounds bounds of the focused view * @param filterText text of the view to be filled + * @param packageName package name of the activity that is filled */ public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response, - @NonNull Rect anchorBounds, @Nullable String filterText) { + @NonNull Rect anchorBounds, @Nullable String filterText, @NonNull String packageName) { + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_FILL_UI)) + .setPackageName(packageName) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN, + filterText == null ? 0 : filterText.length()) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, + response.getDatasets() == null ? 0 : response.getDatasets().size()); + mHandler.post(() -> { if (!hasCallback()) { return; @@ -164,6 +176,7 @@ public final class AutoFillUI { mWindowToken, anchorBounds, filterText, new FillUi.Callback() { @Override public void onResponsePicked(FillResponse response) { + log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL); hideFillUiUiThread(); if (mCallback != null) { mCallback.authenticate(response.getAuthentication()); @@ -172,17 +185,25 @@ public final class AutoFillUI { @Override public void onDatasetPicked(Dataset dataset) { + log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); hideFillUiUiThread(); if (mCallback != null) { mCallback.fill(dataset); } - // TODO(b/33197203): add MetricsLogger call } @Override public void onCanceled() { + log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); hideFillUiUiThread(); - // TODO(b/33197203): add MetricsLogger call + } + + @Override + public void onDestroy() { + if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + } + mMetricsLogger.write(log); } }); mCallback.onEvent(focusedId, EVENT_INPUT_SHOWN); @@ -192,7 +213,16 @@ public final class AutoFillUI { /** * Shows the UI asking the user to save for autofill. */ - public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) { + public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info, + @NonNull String packageName) { + int numIds = 0; + numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length; + numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length; + + LogMaker log = (new LogMaker(MetricsProto.MetricsEvent.AUTOFILL_SAVE_UI)) + .setPackageName(packageName).addTaggedData( + MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds); + mHandler.post(() -> { if (!hasCallback()) { return; @@ -202,16 +232,16 @@ public final class AutoFillUI { new SaveUi.OnSaveListener() { @Override public void onSave() { + log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); hideSaveUiUiThread(); if (mCallback != null) { mCallback.save(); } - // TODO(b/33197203): add MetricsLogger call } @Override public void onCancel(IntentSender listener) { - // TODO(b/33197203): add MetricsLogger call + log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS); hideSaveUiUiThread(); if (listener != null) { try { @@ -225,6 +255,14 @@ public final class AutoFillUI { mCallback.cancelSave(); } } + + @Override + public void onDestroy() { + if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) { + log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); + } + mMetricsLogger.write(log); + } }, mSaveTimeoutMs); }); } @@ -247,11 +285,17 @@ public final class AutoFillUI { } public void dump(PrintWriter pw) { - pw.println("AufoFill UI"); + pw.println("Autofill UI"); final String prefix = " "; - pw.print(prefix); pw.print("showsFillUi: "); pw.println(mFillUi != null); + final String prefix2 = " "; pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null); pw.print(prefix); pw.print("save timeout: "); pw.println(mSaveTimeoutMs); + if (mFillUi != null) { + pw.print(prefix); pw.println("showsFillUi: true"); + mFillUi.dump(pw, prefix2); + } else { + pw.print(prefix); pw.println("showsFillUi: false"); + } } @android.annotation.UiThread diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index a7d9fe96d0da..a8c87523117e 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -39,6 +39,7 @@ import android.widget.ListView; import com.android.internal.R; import libcore.util.Objects; +import java.io.PrintWriter; import java.util.ArrayList; final class FillUi { @@ -50,6 +51,7 @@ final class FillUi { void onResponsePicked(@NonNull FillResponse response); void onDatasetPicked(@NonNull Dataset dataset); void onCanceled(); + void onDestroy(); } private final Rect mAnchorBounds = new Rect(); @@ -63,6 +65,7 @@ final class FillUi { private final @Nullable ArrayAdapter<ViewItem> mAdapter; private @Nullable String mFilterText; + private final String mAccessibilityTitle; private int mContentWidth; private int mContentHeight; @@ -76,6 +79,8 @@ final class FillUi { mAnchorBounds.set(anchorBounds); mCallback = callback; + mAccessibilityTitle = context.getString(R.string.autofill_picker_accessibility_title); + if (response.getAuthentication() != null) { mListView = null; mAdapter = null; @@ -201,6 +206,7 @@ final class FillUi { public void destroy() { throwIfDestroyed(); + mCallback.onDestroy(); mWindow.hide(); mDestroyed = true; } @@ -319,6 +325,7 @@ final class FillUi { public void show(int desiredWidth, int desiredHeight, Rect anchorBounds) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.setTitle("FillUi"); params.token = mActivityToken; params.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; @@ -327,6 +334,7 @@ final class FillUi { | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + params.accessibilityTitle = mAccessibilityTitle; mWm.getDefaultDisplay().getRealSize(mTempPoint); final int screenWidth = mTempPoint.x; @@ -377,4 +385,16 @@ final class FillUi { } } } + + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("mAnchorBounds: "); pw.println(mAnchorBounds); + pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null); + pw.print(prefix); pw.print("mListView: "); pw.println(mListView); + pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter != null); + pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText); + pw.print(prefix); pw.print("mAccessibilityTitle: "); pw.println(mAccessibilityTitle); + pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth); + pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight); + pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed); + } } diff --git a/services/autofill/java/com/android/server/autofill/ui/Helper.java b/services/autofill/java/com/android/server/autofill/ui/Helper.java new file mode 100644 index 000000000000..996e4213ac44 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/ui/Helper.java @@ -0,0 +1,26 @@ +/* + * 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.autofill.ui; + +final class Helper { + + static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable + static final boolean VERBOSE = false; + private Helper() { + throw new UnsupportedOperationException("contains static members only"); + } +} diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 3f409ade68ed..509351bf0858 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -16,6 +16,8 @@ package com.android.server.autofill.ui; +import static com.android.server.autofill.ui.Helper.DEBUG; + import android.annotation.NonNull; import android.app.Dialog; import android.content.Context; @@ -23,6 +25,7 @@ import android.content.IntentSender; import android.os.Handler; import android.service.autofill.SaveInfo; import android.text.format.DateUtils; +import android.util.Slog; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; @@ -37,22 +40,66 @@ import com.android.server.UiThread; * Autofill Save Prompt */ final class SaveUi { + + private static final String TAG = "SaveUi"; + public interface OnSaveListener { void onSave(); void onCancel(IntentSender listener); + void onDestroy(); + } + + private class OneTimeListener implements OnSaveListener { + + private final OnSaveListener mRealListener; + private boolean mDone; + + OneTimeListener(OnSaveListener realListener) { + mRealListener = realListener; + } + + @Override + public void onSave() { + if (DEBUG) Slog.d(TAG, "onSave(): " + mDone); + if (mDone) { + return; + } + mDone = true; + mRealListener.onSave(); + } + + @Override + public void onCancel(IntentSender listener) { + if (DEBUG) Slog.d(TAG, "onCancel(): " + mDone); + if (mDone) { + return; + } + mDone = true; + mRealListener.onCancel(listener); + } + + @Override + public void onDestroy() { + if (DEBUG) Slog.d(TAG, "onDestroy(): " + mDone); + if (mDone) { + return; + } + mDone = true; + mRealListener.onDestroy(); + } } private final Handler mHandler = UiThread.getHandler(); private final @NonNull Dialog mDialog; - private final @NonNull OnSaveListener mListener; + private final @NonNull OneTimeListener mListener; private boolean mDestroyed; SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info, @NonNull OnSaveListener listener, int lifeTimeMs) { - mListener = listener; + mListener = new OneTimeListener(listener); final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.autofill_save, null); @@ -117,11 +164,17 @@ final class SaveUi { mDialog.show(); - mHandler.postDelayed(() -> mListener.onCancel(null), lifeTimeMs); + mHandler.postDelayed(() -> { + if (!mListener.mDone) { + mListener.onCancel(null); + Slog.d(TAG, "Save snackbar timed out after " + lifeTimeMs + "ms"); + } + }, lifeTimeMs); } void destroy() { throwIfDestroyed(); + mListener.onDestroy(); mHandler.removeCallbacksAndMessages(mListener); mDialog.dismiss(); mDestroyed = true; diff --git a/services/core/Android.mk b/services/core/Android.mk index 1864d3407cd7..794ece65b03d 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -23,7 +23,9 @@ LOCAL_JAVA_LIBRARIES := \ android.hardware.power@1.0-java \ android.hardware.tv.cec@1.0-java -LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \ +LOCAL_STATIC_JAVA_LIBRARIES := \ + tzdata_shared2 \ + tzdata_update2 \ android.hidl.base@1.0-java-static \ android.hardware.biometrics.fingerprint@2.1-java-static \ diff --git a/services/core/java/com/android/server/BackgroundDexOptJobService.java b/services/core/java/com/android/server/BackgroundDexOptJobService.java deleted file mode 100644 index 69e6ac50fa8a..000000000000 --- a/services/core/java/com/android/server/BackgroundDexOptJobService.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; - -import android.app.job.JobInfo; -import android.app.job.JobParameters; -import android.app.job.JobScheduler; -import android.app.job.JobService; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.os.Environment; -import android.os.ServiceManager; -import android.os.storage.StorageManager; -import android.util.ArraySet; -import android.util.Log; -import com.android.server.pm.PackageManagerService; - -import java.io.File; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.TimeUnit; - -public class BackgroundDexOptJobService extends JobService { - private static final String TAG = "BackgroundDexOptJobService"; - - private static final boolean DEBUG = false; - - private static final int JOB_IDLE_OPTIMIZE = 800; - private static final int JOB_POST_BOOT_UPDATE = 801; - - private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG - ? TimeUnit.MINUTES.toMillis(1) - : TimeUnit.DAYS.toMillis(1); - - private static ComponentName sDexoptServiceName = new ComponentName( - "android", - BackgroundDexOptJobService.class.getName()); - - /** - * Set of failed packages remembered across job runs. - */ - static final ArraySet<String> sFailedPackageNames = new ArraySet<String>(); - - /** - * Atomics set to true if the JobScheduler requests an abort. - */ - final AtomicBoolean mAbortPostBootUpdate = new AtomicBoolean(false); - final AtomicBoolean mAbortIdleOptimization = new AtomicBoolean(false); - - /** - * Atomic set to true if one job should exit early because another job was started. - */ - final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); - - private final File mDataDir = Environment.getDataDirectory(); - - public static void schedule(Context context) { - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - // Schedule a one-off job which scans installed packages and updates - // out-of-date oat files. - js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName) - .setMinimumLatency(TimeUnit.MINUTES.toMillis(1)) - .setOverrideDeadline(TimeUnit.MINUTES.toMillis(1)) - .build()); - - // Schedule a daily job which scans installed packages and compiles - // those with fresh profiling data. - js.schedule(new JobInfo.Builder(JOB_IDLE_OPTIMIZE, sDexoptServiceName) - .setRequiresDeviceIdle(true) - .setRequiresCharging(true) - .setPeriodic(IDLE_OPTIMIZATION_PERIOD) - .build()); - - if (DEBUG_DEXOPT) { - Log.i(TAG, "Jobs scheduled"); - } - } - - public static void notifyPackageChanged(String packageName) { - // The idle maintanance job skips packages which previously failed to - // compile. The given package has changed and may successfully compile - // now. Remove it from the list of known failing packages. - synchronized (sFailedPackageNames) { - sFailedPackageNames.remove(packageName); - } - } - - // Returns the current battery level as a 0-100 integer. - private int getBatteryLevel() { - IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent intent = registerReceiver(null, filter); - int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - - if (level < 0 || scale <= 0) { - // Battery data unavailable. This should never happen, so assume the worst. - return 0; - } - - return (100 * level / scale); - } - - private long getLowStorageThreshold() { - @SuppressWarnings("deprecation") - final long lowThreshold = StorageManager.from(this).getStorageLowBytes(mDataDir); - if (lowThreshold == 0) { - Log.e(TAG, "Invalid low storage threshold"); - } - - return lowThreshold; - } - - private boolean runPostBootUpdate(final JobParameters jobParams, - final PackageManagerService pm, final ArraySet<String> pkgs) { - if (mExitPostBootUpdate.get()) { - // This job has already been superseded. Do not start it. - return false; - } - new Thread("BackgroundDexOptService_PostBootUpdate") { - @Override - public void run() { - postBootUpdate(jobParams, pm, pkgs); - } - - }.start(); - return true; - } - - private void postBootUpdate(JobParameters jobParams, PackageManagerService pm, - ArraySet<String> pkgs) { - // Load low battery threshold from the system config. This is a 0-100 integer. - final int lowBatteryThreshold = getResources().getInteger( - com.android.internal.R.integer.config_lowBatteryWarningLevel); - final long lowThreshold = getLowStorageThreshold(); - - mAbortPostBootUpdate.set(false); - - for (String pkg : pkgs) { - if (mAbortPostBootUpdate.get()) { - // JobScheduler requested an early abort. - return; - } - if (mExitPostBootUpdate.get()) { - // Different job, which supersedes this one, is running. - break; - } - if (getBatteryLevel() < lowBatteryThreshold) { - // Rather bail than completely drain the battery. - break; - } - long usableSpace = mDataDir.getUsableSpace(); - if (usableSpace < lowThreshold) { - // Rather bail than completely fill up the disk. - Log.w(TAG, "Aborting background dex opt job due to low storage: " + - usableSpace); - break; - } - - if (DEBUG_DEXOPT) { - Log.i(TAG, "Updating package " + pkg); - } - - // Update package if needed. Note that there can be no race between concurrent - // jobs because PackageDexOptimizer.performDexOpt is synchronized. - - // checkProfiles is false to avoid merging profiles during boot which - // might interfere with background compilation (b/28612421). - // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will - // behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a - // trade-off worth doing to save boot time work. - pm.performDexOpt(pkg, - /* checkProfiles */ false, - PackageManagerService.REASON_BOOT, - /* force */ false); - } - // Ran to completion, so we abandon our timeslice and do not reschedule. - jobFinished(jobParams, /* reschedule */ false); - } - - private boolean runIdleOptimization(final JobParameters jobParams, - final PackageManagerService pm, final ArraySet<String> pkgs) { - new Thread("BackgroundDexOptService_IdleOptimization") { - @Override - public void run() { - idleOptimization(jobParams, pm, pkgs); - } - }.start(); - return true; - } - - private void idleOptimization(JobParameters jobParams, PackageManagerService pm, - ArraySet<String> pkgs) { - Log.i(TAG, "Performing idle optimizations"); - // If post-boot update is still running, request that it exits early. - mExitPostBootUpdate.set(true); - - mAbortIdleOptimization.set(false); - - final long lowThreshold = getLowStorageThreshold(); - for (String pkg : pkgs) { - if (mAbortIdleOptimization.get()) { - // JobScheduler requested an early abort. - return; - } - - synchronized (sFailedPackageNames) { - if (sFailedPackageNames.contains(pkg)) { - // Skip previously failing package - continue; - } - } - - long usableSpace = mDataDir.getUsableSpace(); - if (usableSpace < lowThreshold) { - // Rather bail than completely fill up the disk. - Log.w(TAG, "Aborting background dex opt job due to low storage: " + - usableSpace); - break; - } - - // Conservatively add package to the list of failing ones in case performDexOpt - // never returns. - synchronized (sFailedPackageNames) { - sFailedPackageNames.add(pkg); - } - // Optimize package if needed. Note that there can be no race between - // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. - if (pm.performDexOpt(pkg, - /* checkProfiles */ true, - PackageManagerService.REASON_BACKGROUND_DEXOPT, - /* force */ false)) { - // Dexopt succeeded, remove package from the list of failing ones. - synchronized (sFailedPackageNames) { - sFailedPackageNames.remove(pkg); - } - } - } - // Ran to completion, so we abandon our timeslice and do not reschedule. - jobFinished(jobParams, /* reschedule */ false); - } - - @Override - public boolean onStartJob(JobParameters params) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "onStartJob"); - } - - // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from - // the checks above. This check is not "live" - the value is determined by a background - // restart with a period of ~1 minute. - PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); - if (pm.isStorageLow()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Low storage, skipping this run"); - } - return false; - } - - final ArraySet<String> pkgs = pm.getOptimizablePackages(); - if (pkgs == null || pkgs.isEmpty()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "No packages to optimize"); - } - return false; - } - - if (params.getJobId() == JOB_POST_BOOT_UPDATE) { - return runPostBootUpdate(params, pm, pkgs); - } else { - return runIdleOptimization(params, pm, pkgs); - } - } - - @Override - public boolean onStopJob(JobParameters params) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "onStopJob"); - } - - if (params.getJobId() == JOB_POST_BOOT_UPDATE) { - mAbortPostBootUpdate.set(true); - } else { - mAbortIdleOptimization.set(true); - } - return false; - } -} diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index bcee2c1bd9ea..c946d0937017 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -146,6 +146,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final LockPatternUtils mLockPatternUtils; private final NotificationManager mNotificationManager; private final UserManager mUserManager; + private final DevicePolicyManager mDevicePolicyManager; private final IActivityManager mActivityManager; private final KeyStore mKeyStore; @@ -333,6 +334,10 @@ public class LockSettingsService extends ILockSettings.Stub { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + public DevicePolicyManager getDevicePolicyManager() { + return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + } + public KeyStore getKeyStore() { return KeyStore.getInstance(); } @@ -380,6 +385,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage = injector.getStorage(); mNotificationManager = injector.getNotificationManager(); mUserManager = injector.getUserManager(); + mDevicePolicyManager = injector.getDevicePolicyManager(); mStrongAuthTracker = injector.getStrongAuthTracker(); mStrongAuthTracker.register(mStrongAuth); @@ -1482,7 +1488,7 @@ public class LockSettingsService extends ILockSettings.Stub { return VerifyCredentialResponse.OK; } - if (TextUtils.isEmpty(credential)) { + if (storedHash == null || TextUtils.isEmpty(credential)) { return VerifyCredentialResponse.ERROR; } @@ -2015,14 +2021,17 @@ public class LockSettingsService extends ILockSettings.Stub { } } long handle = getSyntheticPasswordHandleLocked(userId); - AuthenticationToken auth = mSpManager.unwrapPasswordBasedSyntheticPassword( - getGateKeeperService(), handle, savedCredential, userId).authToken; + AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), handle, savedCredential, userId); + VerifyCredentialResponse response = authResult.gkResponse; + AuthenticationToken auth = authResult.authToken; if (auth != null) { // We are performing a trusted credential change i.e. a correct existing credential // is provided setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId); mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); - } else { + } else if (response != null + && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){ // We are performing an untrusted credential change i.e. by DevicePolicyManager. // So provision a new SP and SID. This would invalidate existing escrow tokens. // Still support this for now but this flow will be removed in the next release. @@ -2031,6 +2040,10 @@ public class LockSettingsService extends ILockSettings.Stub { initializeSyntheticPasswordLocked(null, credential, credentialType, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, null); mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); + } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ { + Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " + + (response != null ? "rate limit exceeded" : "failed")); + return; } notifyActivePasswordMetricsAvailable(credential, userId); @@ -2042,7 +2055,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { enableSyntheticPasswordLocked(); - // Migrate to synthetic password based credentials if ther user has no password, + // Migrate to synthetic password based credentials if the user has no password, // the token can then be activated immediately. AuthenticationToken auth = null; if (!isUserSecure(userId)) { @@ -2201,22 +2214,20 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.i(TAG, "Managed profile can have escrow token"); return; } - DevicePolicyManager dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); // Devices with Device Owner should have escrow enabled on all users. - if (dpm.getDeviceOwnerComponentOnAnyUser() != null) { + if (mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser() != null) { Slog.i(TAG, "Corp-owned device can have escrow token"); return; } // We could also have a profile owner on the given (non-managed) user for unicorn cases - if (dpm.getProfileOwnerAsUser(userId) != null) { + if (mDevicePolicyManager.getProfileOwnerAsUser(userId) != null) { Slog.i(TAG, "User with profile owner can have escrow token"); return; } // If the device is yet to be provisioned (still in SUW), there is still // a chance that Device Owner will be set on the device later, so postpone // disabling escrow token for now. - if (!dpm.isDeviceProvisioned()) { + if (!mDevicePolicyManager.isDeviceProvisioned()) { Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned"); return; } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 3667ecdec472..8e6310fdacbb 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2721,7 +2721,7 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public int getPasswordType() { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "no permission to access the crypt keeper"); waitForReady(); @@ -2747,7 +2747,7 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public void setField(String field, String contents) throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "no permission to access the crypt keeper"); waitForReady(); @@ -2767,7 +2767,7 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public String getField(String field) throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "no permission to access the crypt keeper"); waitForReady(); @@ -2793,7 +2793,7 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public boolean isConvertibleToFBE() throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "no permission to access the crypt keeper"); waitForReady(); @@ -2809,7 +2809,7 @@ class StorageManagerService extends IStorageManager.Stub @Override public String getPassword() throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "only keyguard can retrieve password"); if (!isReady()) { @@ -2834,7 +2834,7 @@ class StorageManagerService extends IStorageManager.Stub @Override public void clearPassword() throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, "only keyguard can clear password"); if (!isReady()) { diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java index 62678801a9a2..2517613c03e0 100644 --- a/services/core/java/com/android/server/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/SyntheticPasswordManager.java @@ -526,7 +526,7 @@ public class SyntheticPasswordManager { * RESPONSE_OK, since user authentication failures are detected earlier when trying to * decrypt SP. */ - public VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, + public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, @NonNull AuthenticationToken auth, long challenge, int userId) throws RemoteException { byte[] spHandle = loadSyntheticPasswordHandle(userId); if (spHandle == null) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index accae0da8a8e..f954f75aa05e 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -35,7 +35,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; -import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.INotificationManager; import android.app.Notification; @@ -64,7 +63,6 @@ import android.content.pm.Signature; import android.content.pm.UserInfo; import android.database.Cursor; import android.database.sqlite.SQLiteStatement; -import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -80,7 +78,6 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -113,7 +110,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -158,6 +154,11 @@ public class AccountManagerService public void onUnlockUser(int userHandle) { mService.onUnlockUser(userHandle); } + + @Override + public void onCleanupUser(int userHandle) { + mService.onCleanupUser(userHandle); + } } final Context mContext; @@ -303,18 +304,6 @@ public class AccountManagerService } }, intentFilter); - IntentFilter userFilter = new IntentFilter(); - userFilter.addAction(Intent.ACTION_USER_REMOVED); - mContext.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_REMOVED.equals(action)) { - onUserRemoved(intent); - } - } - }, UserHandle.ALL, userFilter, null, null); - injector.addLocalService(new AccountManagerInternalImpl()); // Need to cancel account request notifications if the update/install can access the account @@ -1133,16 +1122,12 @@ public class AccountManagerService } } - private void onUserRemoved(Intent intent) { - int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - if (userId < 1) return; - + private void onCleanupUser(int userId) { + Log.i(TAG, "onCleanupUser " + userId); UserAccounts accounts; - boolean userUnlocked; synchronized (mUsers) { accounts = mUsers.get(userId); mUsers.remove(userId); - userUnlocked = mLocalUnlockedUsers.get(userId); mLocalUnlockedUsers.delete(userId); } if (accounts != null) { @@ -1150,18 +1135,6 @@ public class AccountManagerService accounts.accountsDb.close(); } } - Log.i(TAG, "Removing database files for user " + userId); - File dbFile = new File(mInjector.getDeDatabaseName(userId)); - - AccountsDb.deleteDbFileWarnIfFailed(dbFile); - // Remove CE file if user is unlocked, or FBE is not enabled - boolean fbeEnabled = StorageManager.isFileEncryptedNativeOrEmulated(); - if (!fbeEnabled || userUnlocked) { - File ceDb = new File(mInjector.getCeDatabaseName(userId)); - if (ceDb.exists()) { - AccountsDb.deleteDbFileWarnIfFailed(ceDb); - } - } } @VisibleForTesting diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 100d8212eacc..df250b19beba 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -105,16 +105,16 @@ final class ActivityManagerConstants extends ContentObserver { } private void updateConstants() { + final String setting = Settings.Global.getString(mResolver, + Settings.Global.ACTIVITY_MANAGER_CONSTANTS); synchronized (mService) { try { - mParser.setString(Settings.Global.getString(mResolver, - Settings.Global.ACTIVITY_MANAGER_CONSTANTS)); + mParser.setString(setting); } catch (IllegalArgumentException e) { // Failed to parse the settings string, log this and move on // with defaults. Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e); } - ENFORCE_BG_CHECK = mParser.getBoolean(KEY_ENFORCE_BG_CHECK, DEFAULT_ENFORCE_BG_CHECK); MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES, DEFAULT_MAX_CACHED_PROCESSES); diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index ebbce0227b3e..918747b37076 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -251,7 +251,8 @@ class ActivityMetricsLogger { * ActivityManagerInternal.APP_TRANSITION_* reasons. */ void notifyTransitionStarting(SparseIntArray stackIdReasons) { - if (!isAnyTransitionActive() || mLoggedTransitionStarting) { + // TODO (b/36339388): Figure out why stackIdReasons can be null + if (stackIdReasons == null || !isAnyTransitionActive() || mLoggedTransitionStarting) { return; } mCurrentTransitionDelayMs = calculateCurrentDelay(); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 2e26bedd50f8..2b2471b28aa5 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1953,11 +1953,6 @@ final class ActivityRecord implements AppWindowContainerListener { } void setRequestedOrientation(int requestedOrientation) { - if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) { - // Fixed screen orientation isn't supported when activities aren't in full screen mode. - return; - } - final int displayId = getDisplayId(); final Configuration displayConfig = mStackSupervisor.getDisplayOverrideConfiguration(displayId); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 42efe0b5d8e0..217515b936dd 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.START_ANY_ACTIVITY; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; @@ -1612,8 +1613,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - // Check if the caller can launch anything. - final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid, + // Check if the caller can manage activity stacks. + final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid, callingUid); if (startAnyPerm == PERMISSION_GRANTED) { if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 36a913fb9c53..f927ccea1d5d 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -857,17 +857,26 @@ class AppErrors { ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); - String[] nativeProcs = NATIVE_STACKS_OF_INTEREST; - // don't dump native PIDs for background ANRs - File tracesFile = null; + // don't dump native PIDs for background ANRs unless it is the process of interest + String[] nativeProcs = null; if (isSilentANR) { - tracesFile = mService.dumpStackTraces(true, firstPids, null, lastPids, - null); + for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { + if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) { + nativeProcs = new String[] { app.processName }; + break; + } + } } else { - tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids, - nativeProcs); + nativeProcs = NATIVE_STACKS_OF_INTEREST; } + // For background ANRs, don't pass the ProcessCpuTracker to + // avoid spending 1/2 second collecting stats to rank lastPids. + File tracesFile = mService.dumpStackTraces(true, firstPids, + (isSilentANR) ? null : processCpuTracker, + (isSilentANR) ? null : lastPids, + nativeProcs); + String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { mService.updateCpuStatsNow(); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 278789568b85..dd3d4e0d1be2 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1152,17 +1152,14 @@ public final class BroadcastQueue { skip = true; } } - final boolean visibleToInstantApps = - (r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0; if (!skip && info.activityInfo.applicationInfo.isInstantApp() - && !visibleToInstantApps && r.callingUid != info.activityInfo.applicationInfo.uid) { Slog.w(TAG, "Instant App Denial: receiving " + r.intent + " to " + component.flattenToShortString() + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")" - + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS"); + + " Instant Apps do not support manifest receivers"); skip = true; } if (!skip && r.callerInstantApp diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java index dec2f77b6455..8c6430c8a2ae 100644 --- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java +++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java @@ -16,6 +16,8 @@ package com.android.server.connectivity.tethering; +import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; + import android.net.INetd; import android.net.IpPrefix; import android.net.LinkAddress; @@ -48,7 +50,6 @@ import java.util.Objects; public class IPv6TetheringInterfaceServices { private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); - private static final int RFC7421_IP_PREFIX_LENGTH = 64; private final String mIfName; private final INetworkManagementService mNMService; @@ -124,7 +125,7 @@ public class IPv6TetheringInterfaceServices { params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); for (LinkAddress linkAddr : v6only.getLinkAddresses()) { - if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue; + if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue; final IpPrefix prefix = new IpPrefix( linkAddr.getAddress(), linkAddr.getPrefixLength()); @@ -206,7 +207,7 @@ public class IPv6TetheringInterfaceServices { for (Inet6Address dns : deprecatedDnses) { final String dnsString = dns.getHostAddress(); try { - netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); + netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH); } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e); } @@ -223,7 +224,7 @@ public class IPv6TetheringInterfaceServices { for (Inet6Address dns : addedDnses) { final String dnsString = dns.getHostAddress(); try { - netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); + netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH); } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to add local dns IP: " + dnsString, e); newDnses.remove(dns); diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 32621515130d..bdba64f72995 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -97,7 +97,6 @@ public class FingerprintService extends SystemService implements IHwBinder.Death static final String TAG = "FingerprintService"; static final boolean DEBUG = true; private static final String FP_DATA_DIR = "fpdata"; - private static final String FINGERPRINT_HIDL = "fingerprint_hal"; private static final int MSG_USER_SWITCHING = 10; private static final String ACTION_LOCKOUT_RESET = "com.android.server.fingerprint.ACTION_LOCKOUT_RESET"; @@ -219,7 +218,7 @@ public class FingerprintService extends SystemService implements IHwBinder.Death public synchronized IBiometricsFingerprint getFingerprintDaemon() { if (mDaemon == null) { try { - mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL); + mDaemon = IBiometricsFingerprint.getService(); } catch (java.util.NoSuchElementException e) { // Service doesn't exist or cannot be opened. Logged below. } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index be8aaf02db41..3dcc5d997e08 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -22,10 +22,10 @@ import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED; -import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL; -import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CANCEL_ALL; -import static android.service.notification.NotificationListenerService.REASON_DELEGATE_CLICK; -import static android.service.notification.NotificationListenerService.REASON_DELEGATE_ERROR; +import static android.service.notification.NotificationListenerService.REASON_CANCEL; +import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; +import static android.service.notification.NotificationListenerService.REASON_CLICK; +import static android.service.notification.NotificationListenerService.REASON_ERROR; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL; import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL; @@ -88,7 +88,6 @@ import android.database.ContentObserver; import android.media.AudioManager; import android.media.AudioManagerInternal; import android.media.IRingtonePlayer; -import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -179,7 +178,6 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -543,7 +541,7 @@ public class NotificationManagerService extends SystemService { @Override public void onClearAll(int callingUid, int callingPid, int userId) { synchronized (mNotificationLock) { - cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null, + cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null, /*includeCurrentProfiles*/ true); } } @@ -567,7 +565,7 @@ public class NotificationManagerService extends SystemService { cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), sbn.getId(), Notification.FLAG_AUTO_CANCEL, Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), - REASON_DELEGATE_CLICK, null); + REASON_CLICK, null); } } @@ -596,7 +594,7 @@ public class NotificationManagerService extends SystemService { String pkg, String tag, int id, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, - true, userId, REASON_DELEGATE_CANCEL, null); + true, userId, REASON_CANCEL, null); } @Override @@ -631,7 +629,7 @@ public class NotificationManagerService extends SystemService { Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, - REASON_DELEGATE_ERROR, null); + REASON_ERROR, null); long ident = Binder.clearCallingIdentity(); try { ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1, @@ -1658,8 +1656,7 @@ public class NotificationManagerService extends SystemService { public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted) { checkCallerIsSystem(); - return mRankingHelper.getNotificationChannel - (pkg, uid, channelId, includeDeleted); + return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted); } @Override @@ -1675,6 +1672,27 @@ public class NotificationManagerService extends SystemService { } @Override + public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups( + String pkg) { + checkCallerIsSystemOrSameApp(pkg); + return new ParceledListSlice<>(new ArrayList( + mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid()))); + } + + @Override + public void deleteNotificationChannelGroup(String pkg, String channelGroupId) { + checkCallerIsSystemOrSameApp(pkg); + + List<String> deletedChannelIds = mRankingHelper.deleteNotificationChannelGroup( + pkg, Binder.getCallingUid(), channelGroupId); + for (int i = 0; i < deletedChannelIds.size(); i++) { + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannelIds.get(i), 0, 0, true, + UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null); + } + savePolicyFile(); + } + + @Override public void updateNotificationChannelForPackage(String pkg, int uid, NotificationChannel channel) { enforceSystemOrSystemUI("Caller not system or systemui"); @@ -1698,6 +1716,12 @@ public class NotificationManagerService extends SystemService { } @Override + public int getDeletedChannelCount(String pkg, int uid) { + enforceSystemOrSystemUI("getDeletedChannelCount"); + return mRankingHelper.getDeletedChannelCount(pkg, uid); + } + + @Override public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage( String pkg, int uid, boolean includeDeleted) { checkCallerIsSystem(); @@ -3349,7 +3373,7 @@ public class NotificationManagerService extends SystemService { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(n, - NotificationListenerService.REASON_DELEGATE_ERROR); + NotificationListenerService.REASON_ERROR); mHandler.post(new Runnable() { @Override public void run() { @@ -3996,8 +4020,8 @@ public class NotificationManagerService extends SystemService { // Record usage stats // TODO: add unbundling stats? switch (reason) { - case REASON_DELEGATE_CANCEL: - case REASON_DELEGATE_CANCEL_ALL: + case REASON_CANCEL: + case REASON_CANCEL_ALL: case REASON_LISTENER_CANCEL: case REASON_LISTENER_CANCEL_ALL: mUsageStats.registerDismissedByUser(r); @@ -4057,7 +4081,7 @@ public class NotificationManagerService extends SystemService { // Ideally we'd do this in the caller of this method. However, that would // require the caller to also find the notification. - if (reason == REASON_DELEGATE_CLICK) { + if (reason == REASON_CLICK) { mUsageStats.registerClickedByUser(r); } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 4b1804c8e7a7..02f92fedb85d 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -15,8 +15,6 @@ */ package com.android.server.notification; -import static android.app.NotificationManager.IMPORTANCE_NONE; - import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -69,7 +67,6 @@ public class RankingHelper implements RankingConfig { private static final String ATT_VERSION = "version"; private static final String ATT_NAME = "name"; - private static final String ATT_NAME_RES_ID = "name_res_id"; private static final String ATT_UID = "uid"; private static final String ATT_ID = "id"; private static final String ATT_PRIORITY = "priority"; @@ -195,14 +192,9 @@ public class RankingHelper implements RankingConfig { if (TAG_GROUP.equals(tagName)) { String id = parser.getAttributeValue(null, ATT_ID); CharSequence groupName = parser.getAttributeValue(null, ATT_NAME); - int groupNameRes = safeInt(parser, ATT_NAME_RES_ID, 0); if (!TextUtils.isEmpty(id)) { - NotificationChannelGroup group = null; - if (groupName != null) { - group = new NotificationChannelGroup(id, groupName); - } else { - group = new NotificationChannelGroup(id, groupNameRes); - } + NotificationChannelGroup group + = new NotificationChannelGroup(id, groupName); r.groups.put(id, group); } } @@ -210,19 +202,12 @@ public class RankingHelper implements RankingConfig { if (TAG_CHANNEL.equals(tagName)) { String id = parser.getAttributeValue(null, ATT_ID); CharSequence channelName = parser.getAttributeValue(null, ATT_NAME); - int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, 0); int channelImportance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); - if (!TextUtils.isEmpty(id)) { - NotificationChannel channel; - if (channelName != null) { - channel = new NotificationChannel(id, channelName, - channelImportance); - } else { - channel = new NotificationChannel(id, channelNameRes, - channelImportance); - } + if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) { + NotificationChannel channel = new NotificationChannel(id, + channelName, channelImportance); channel.populateFromXml(parser); r.channels.put(id, channel); } @@ -302,7 +287,7 @@ public class RankingHelper implements RankingConfig { NotificationChannel channel; channel = new NotificationChannel( NotificationChannel.DEFAULT_CHANNEL_ID, - R.string.default_notification_channel_label, + mContext.getString(R.string.default_notification_channel_label), r.importance); channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); channel.setLockscreenVisibility(r.visibility); @@ -482,8 +467,7 @@ public class RankingHelper implements RankingConfig { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(group); Preconditions.checkNotNull(group.getId()); - Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()) - || group.getNameResId() != 0); + Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName())); Record r = getOrCreateRecord(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -504,8 +488,7 @@ public class RankingHelper implements RankingConfig { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(channel); Preconditions.checkNotNull(channel.getId()); - Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()) - || channel.getNameResId() != 0); + Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())); Record r = getOrCreateRecord(pkg, uid); if (r == null) { throw new IllegalArgumentException("Invalid package"); @@ -524,7 +507,7 @@ public class RankingHelper implements RankingConfig { existing.setDeleted(false); } - existing.setNameResId(channel.getNameResId()); + existing.setName(channel.getName()); MetricsLogger.action(getChannelLog(channel, pkg)); updateConfig(); @@ -669,8 +652,6 @@ public class RankingHelper implements RankingConfig { @Override public void deleteNotificationChannel(String pkg, int uid, String channelId) { - Preconditions.checkNotNull(pkg); - Preconditions.checkNotNull(channelId); Record r = getRecord(pkg, uid); if (r == null) { return; @@ -682,6 +663,7 @@ public class RankingHelper implements RankingConfig { LogMaker lm = getChannelLog(channel, pkg); lm.setType(MetricsProto.MetricsEvent.TYPE_CLOSE); MetricsLogger.action(lm); + updateConfig(); } @Override @@ -694,6 +676,7 @@ public class RankingHelper implements RankingConfig { return; } r.channels.remove(channelId); + updateConfig(); } @Override @@ -710,6 +693,7 @@ public class RankingHelper implements RankingConfig { r.channels.remove(key); } } + updateConfig(); } public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg, @@ -734,12 +718,15 @@ public class RankingHelper implements RankingConfig { final NotificationChannel nc = r.channels.valueAt(i); if (includeDeleted || !nc.isDeleted()) { if (nc.getGroup() != null) { - NotificationChannelGroup ncg = groups.get(nc.getGroup()); - if (ncg == null ) { - ncg = r.groups.get(nc.getGroup()).clone(); - groups.put(nc.getGroup(), ncg); + if (r.groups.get(nc.getGroup()) != null) { + NotificationChannelGroup ncg = groups.get(nc.getGroup()); + if (ncg == null) { + ncg = r.groups.get(nc.getGroup()).clone(); + groups.put(nc.getGroup(), ncg); + + } + ncg.addChannel(nc); } - ncg.addChannel(nc); } else { nonGrouped.addChannel(nc); } @@ -751,8 +738,29 @@ public class RankingHelper implements RankingConfig { return new ParceledListSlice<>(new ArrayList<>(groups.values())); } + public List<String> deleteNotificationChannelGroup(String pkg, int uid, + String groupId) { + List<String> deletedChannelIds = new ArrayList<>(); + Record r = getRecord(pkg, uid); + if (r == null || TextUtils.isEmpty(groupId)) { + return deletedChannelIds; + } + + r.groups.remove(groupId); + + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (groupId.equals(nc.getGroup())) { + nc.setDeleted(true); + deletedChannelIds.add(nc.getId()); + } + } + updateConfig(); + return deletedChannelIds; + } + @Override - @VisibleForTesting public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid) { Record r = getRecord(pkg, uid); @@ -781,6 +789,23 @@ public class RankingHelper implements RankingConfig { return new ParceledListSlice<>(channels); } + public int getDeletedChannelCount(String pkg, int uid) { + Preconditions.checkNotNull(pkg); + int deletedCount = 0; + Record r = getRecord(pkg, uid); + if (r == null) { + return deletedCount; + } + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (nc.isDeleted()) { + deletedCount++; + } + } + return deletedCount; + } + /** * Sets importance. */ diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 7aa96cfddc62..d8900c0546fd 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -49,8 +49,6 @@ public class BackgroundDexOptService extends JobService { private static final boolean DEBUG = false; - private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR; - private static final int JOB_IDLE_OPTIMIZE = 800; private static final int JOB_POST_BOOT_UPDATE = 801; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4ac1cce91402..1d1bf0d195d9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -260,7 +260,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; -import com.android.server.BackgroundDexOptJobService; import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; import com.android.server.FgThread; @@ -272,6 +271,7 @@ import com.android.server.SystemConfig; import com.android.server.SystemServerInitThreadPool; import com.android.server.Watchdog; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PermissionsState.PermissionState; import com.android.server.pm.Settings.DatabaseVersion; @@ -2038,12 +2038,15 @@ public class PackageManagerService extends IPackageManager.Stub { final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; + final boolean instantApp = isInstantApp(pkg.packageName, userId); + for (String permission : pkg.requestedPermissions) { final BasePermission bp; synchronized (mPackages) { bp = mSettings.mPermissions.get(permission); } if (bp != null && (bp.isRuntime() || bp.isDevelopment()) + && (!instantApp || bp.isInstant()) && (grantedPermissions == null || ArrayUtils.contains(grantedPermissions, permission))) { final int flags = permissionsState.getPermissionFlags(permission, userId); @@ -3348,7 +3351,7 @@ public class PackageManagerService extends IPackageManager.Stub { // * The system/shell/root can see metadata for any app // * An installed app can see metadata for 1) other installed apps // and 2) ephemeral apps that have explicitly interacted with it - // * Ephemeral apps can only see their own metadata + // * Ephemeral apps can only see their own data and exposed installed apps // * Holding a signature permission allows seeing instant apps final int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); if (callingAppId != Process.SYSTEM_UID @@ -3358,8 +3361,10 @@ public class PackageManagerService extends IPackageManager.Stub { Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) { final String instantAppPackageName = getInstantAppPackageName(Binder.getCallingUid()); if (instantAppPackageName != null) { - // ephemeral apps can only get information on themselves - if (!instantAppPackageName.equals(p.packageName)) { + // ephemeral apps can only get information on themselves or + // installed apps that are exposed. + if (!instantAppPackageName.equals(p.packageName) + && (ps.getInstantApp(userId) || !p.visibleToInstantApps)) { return null; } } else { @@ -16850,11 +16855,11 @@ public class PackageManagerService extends IPackageManager.Stub { mDexManager.isUsedByOtherApps(pkg.packageName)); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - // Notify BackgroundDexOptJobService that the package has been changed. + // Notify BackgroundDexOptService that the package has been changed. // If this is an update of a package which used to fail to compile, // BDOS will remove it from its blacklist. // TODO: Layering violation - BackgroundDexOptJobService.notifyPackageChanged(pkg.packageName); + BackgroundDexOptService.notifyPackageChanged(pkg.packageName); } if (!args.doRename(res.returnCode, pkg, oldCodePath)) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index a7349fc8454c..751d9af33463 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -147,6 +147,8 @@ class PackageManagerShellCommand extends ShellCommand { return runSetHomeActivity(); case "get-privapp-permissions": return runGetPrivappPermissions(); + case "has-feature": + return runHasFeature(); default: return handleDefaultCommands(cmd); } @@ -1268,6 +1270,28 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private int runHasFeature() { + final PrintWriter err = getErrPrintWriter(); + final String featureName = getNextArg(); + if (featureName == null) { + err.println("Error: expected FEATURE name"); + return 1; + } + final String versionString = getNextArg(); + try { + final int version = (versionString == null) ? 0 : Integer.parseInt(versionString); + final boolean hasFeature = mInterface.hasSystemFeature(featureName, version); + getOutPrintWriter().println(hasFeature); + return hasFeature ? 0 : 1; + } catch (NumberFormatException e) { + err.println("Error: illegal version number " + versionString); + return 1; + } catch (RemoteException e) { + err.println(e.toString()); + return 1; + } + } + private static String checkAbiArgument(String abi) { if (TextUtils.isEmpty(abi)) { throw new IllegalArgumentException("Missing ABI argument"); @@ -1649,6 +1673,9 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" Unsuspends the specified package (as user)."); pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT"); pw.println(" set the default home activity (aka launcher)."); + pw.println(" has-feature FEATURE_NAME [version]"); + pw.println(" prints true and returns exit status 0 when system has a FEATURE_NAME,"); + pw.println(" otherwise prints false and returns exit status 1"); pw.println(); Intent.printIntentArgsHelp(pw , ""); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b9fcf4e39203..a31258c39341 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1493,6 +1493,10 @@ public class UserManagerService extends IUserManager.Stub { listeners[i].onUserRestrictionsChanged(userId, newRestrictionsFinal, prevRestrictionsFinal); } + + final Intent broadcast = new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcastAsUser(broadcast, UserHandle.of(userId)); } }); } @@ -1810,8 +1814,8 @@ public class UserManagerService extends IUserManager.Stub { if (type == XmlPullParser.START_TAG) { if (parser.getName().equals(TAG_RESTRICTIONS)) { synchronized (mGuestRestrictions) { - mGuestRestrictions.putAll( - UserRestrictionsUtils.readRestrictions(parser)); + UserRestrictionsUtils + .readRestrictions(parser, mGuestRestrictions); } } break; diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 36eba8e1b6bb..cb2ed6e0d00f 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -207,6 +207,7 @@ public class UserRestrictionsUtils { } public static void readRestrictions(XmlPullParser parser, Bundle restrictions) { + restrictions.clear(); for (String key : USER_RESTRICTIONS) { final String value = parser.getAttributeValue(null, key); if (value != null) { diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java index 5e17daa0f153..8f95cc74c914 100644 --- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java +++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java @@ -1,6 +1,8 @@ package com.android.server.vr; +import static android.view.Display.INVALID_DISPLAY; + import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; @@ -86,10 +88,8 @@ class CompatibilityDisplay { startVirtualDisplay(); } } else { - // TODO: Remove conditional when launching apps 2D doesn't force VrMode to stop. - if (!DEBUG) { - stopVirtualDisplay(); - } + // Stop virtual display to test exit condition + stopVirtualDisplay(); } } @@ -138,6 +138,19 @@ class CompatibilityDisplay { } } + public int getVirtualDisplayId() { + synchronized(vdLock) { + if (mVirtualDisplay != null) { + int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId(); + if (DEBUG) { + Log.e(TAG, "VD id: " + virtualDisplayId); + } + return virtualDisplayId; + } + } + return INVALID_DISPLAY; + } + private void startVirtualDisplay() { if (DEBUG) { Log.d(TAG, "Request to start VD, DM:" + mDisplayManager); diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java index 58e4bdc36e6a..210aa44c0c03 100644 --- a/services/core/java/com/android/server/vr/VrManagerInternal.java +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -90,6 +90,15 @@ public abstract class VrManagerInternal { public abstract void setPersistentVrModeEnabled(boolean enabled); /** + * Return {@link android.view.Display.INVALID_DISPLAY} if there exists no virtual display + * currently or the display id of the current virtual display. + * + * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display + * currently, else return the display id of the virtual display + */ + public abstract int getCompatibilityDisplayId(); + + /** * Adds listener that reports state changes to persistent VR mode. */ public abstract void addPersistentVrModeStateListener(PersistentVrStateListener listener); diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 8a23173ca208..a00115cba2a2 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -15,6 +15,8 @@ */ package com.android.server.vr; +import static android.view.Display.INVALID_DISPLAY; + import android.Manifest; import android.app.ActivityManager; import android.app.AppOpsManager; @@ -392,6 +394,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @Override + public int getCompatibilityDisplayId() { + return VrManagerService.this.getCompatibilityDisplayId(); + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { @@ -495,6 +502,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @Override + public int getCompatibilityDisplayId() { + return VrManagerService.this.getCompatibilityDisplayId(); + } + + @Override public void addPersistentVrModeStateListener(PersistentVrStateListener listener) { VrManagerService.this.addPersistentVrModeStateListener(listener); } @@ -1054,6 +1066,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } + private int getCompatibilityDisplayId() { + if (mCompatibilityDisplay != null) { + return mCompatibilityDisplay.getVirtualDisplayId(); + } + Slog.w(TAG, "CompatibilityDisplay is null!"); + return INVALID_DISPLAY; + } + private void setPersistentModeAndNotifyListenersLocked(boolean enabled) { if (mPersistentVrModeEnabled == enabled) { return; diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 4df513eb27f4..30e0dedd7c99 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -28,7 +28,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.content.ClipData; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; import android.os.Binder; @@ -39,6 +38,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.MergedConfiguration; import android.util.Slog; import android.view.Display; import android.view.IWindow; @@ -216,13 +216,13 @@ public class Session extends IWindowSession.Stub int requestedWidth, int requestedHeight, int viewFlags, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, - Configuration outConfig, Surface outSurface) { + MergedConfiguration mergedConfiguration, Surface outSurface) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); int res = mService.relayoutWindow(this, window, seq, attrs, requestedWidth, requestedHeight, viewFlags, flags, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, - outStableInsets, outsets, outBackdropFrame, outConfig, outSurface); + outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); return res; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index c0598ca0238d..04403e2712c1 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -27,7 +27,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.ActivityManager.TaskDescription; -import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -38,6 +37,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.util.MergedConfiguration; import android.util.Slog; import android.view.IWindowSession; import android.view.Surface; @@ -78,7 +78,7 @@ class TaskSnapshotSurface implements StartingSurface { final Surface surface = new Surface(); final Rect tmpRect = new Rect(); final Rect tmpFrame = new Rect(); - final Configuration tmpConfiguration = new Configuration(); + final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration(); int fillBackgroundColor = Color.WHITE; synchronized (service.mWindowMap) { layoutParams.type = TYPE_APPLICATION_STARTING; @@ -122,7 +122,7 @@ class TaskSnapshotSurface implements StartingSurface { window.setOuter(snapshotSurface); try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame, - tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpConfiguration, + tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpRect, tmpMergedConfiguration, surface); } catch (RemoteException e) { // Local call. @@ -221,9 +221,9 @@ class TaskSnapshotSurface implements StartingSurface { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, - Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig, - Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, - int displayId) { + Rect stableInsets, Rect outsets, boolean reportDraw, + MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, + boolean alwaysConsumeNavBar, int displayId) { if (reportDraw) { sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5551afec76e8..7539cd4b8cab 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -150,6 +150,7 @@ import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.util.ArraySet; +import android.util.MergedConfiguration; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -1813,7 +1814,7 @@ public class WindowManagerService extends IWindowManager.Stub int requestedHeight, int viewVisibility, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, - Configuration outConfig, Surface outSurface) { + MergedConfiguration mergedConfiguration, Surface outSurface) { int result = 0; boolean configChanged; boolean hasStatusBarPermission = @@ -1925,7 +1926,7 @@ public class WindowManagerService extends IWindowManager.Stub if (viewVisibility == View.VISIBLE && (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING || !win.mAppToken.clientHidden)) { - result = win.relayoutVisibleWindow(outConfig, result, attrChanges, + result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges, oldVisibility); try { result = createSurfaceControl(outSurface, result, win, winAnimator); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4e593d86f7c0..ca5d551e8e0d 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -114,6 +114,7 @@ import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; +import android.util.MergedConfiguration; import android.util.DisplayMetrics; import android.util.Slog; import android.util.TimeUtils; @@ -2265,7 +2266,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - void prepareWindowToDisplayDuringRelayout(Configuration outConfig) { + void prepareWindowToDisplayDuringRelayout(MergedConfiguration mergedConfiguration) { if ((mAttrs.softInputMode & SOFT_INPUT_MASK_ADJUST) == SOFT_INPUT_ADJUST_RESIZE) { mLayoutNeeded = true; @@ -2278,10 +2279,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mTurnOnScreen = true; } if (isConfigChanged()) { - outConfig.setTo(getConfiguration()); - if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: " - + outConfig); - mLastReportedConfiguration.setTo(outConfig); + final Configuration globalConfig = mService.mRoot.getConfiguration(); + final Configuration overrideConfig = getMergedOverrideConfiguration(); + mergedConfiguration.setConfiguration(globalConfig, overrideConfig); + if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + + " visible with new global config: " + globalConfig + + " merged override config: " + overrideConfig); + mLastReportedConfiguration.setTo(getConfiguration()); } } @@ -3027,12 +3031,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP try { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this + ": " + mCompatFrame); - final Configuration newConfig; + final MergedConfiguration mergedConfiguration; if (isConfigChanged()) { - newConfig = new Configuration(getConfiguration()); - mLastReportedConfiguration.setTo(newConfig); + mergedConfiguration = new MergedConfiguration(mService.mRoot.getConfiguration(), + getMergedOverrideConfiguration()); + mLastReportedConfiguration.setTo(mergedConfiguration.getMergedConfiguration()); } else { - newConfig = null; + mergedConfiguration = null; } if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING) Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING"); @@ -3054,7 +3059,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void run() { try { dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, - stableInsets, outsets, reportDraw, newConfig, + stableInsets, outsets, reportDraw, mergedConfiguration, reportOrientation, displayId); } catch (RemoteException e) { // Not a remote call, RemoteException won't be raised. @@ -3063,7 +3068,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP }); } else { dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, - outsets, reportDraw, newConfig, reportOrientation, displayId); + outsets, reportDraw, mergedConfiguration, reportOrientation, displayId); } //TODO (multidisplay): Accessibility supported only for the default display. @@ -3120,14 +3125,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, - Configuration newConfig, boolean reportOrientation, int displayId) + MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId) throws RemoteException { final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing || reportOrientation; mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets, - reportDraw, newConfig, getBackdropFrame(frame), - forceRelayout, mPolicy.isNavBarForcedShownLw(this), displayId); + reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout, + mPolicy.isNavBarForcedShownLw(this), displayId); mDragResizingChangeReported = true; } @@ -4341,8 +4346,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets); } - int relayoutVisibleWindow(Configuration outConfig, int result, - int attrChanges, int oldVisibility) { + int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges, + int oldVisibility) { result |= !isVisibleLw() ? RELAYOUT_RES_FIRST_TIME : 0; if (mAnimatingExit) { Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit=" @@ -4363,7 +4368,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWinAnimator.mEnteringAnimation = true; if ((result & RELAYOUT_RES_FIRST_TIME) != 0) { - prepareWindowToDisplayDuringRelayout(outConfig); + prepareWindowToDisplayDuringRelayout(mergedConfiguration); } if ((attrChanges & FORMAT_CHANGED) != 0) { // If the format can't be changed in place, preserve the old surface until the app draws diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index ac95db5c34b4..b5ed26630b23 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -65,6 +65,7 @@ LOCAL_SHARED_LIBRARIES += \ libinputflinger \ libinputservice \ libsensorservice \ + libsensorservicehidl \ libskia \ libgui \ libusbhost \ @@ -88,5 +89,6 @@ LOCAL_SHARED_LIBRARIES += \ android.hardware.tv.input@1.0 \ android.hardware.vibrator@1.0 \ android.hardware.vr@1.0 \ + android.frameworks.sensorservice@1.0 \ -LOCAL_STATIC_LIBRARIES += libscrypt_static
\ No newline at end of file +LOCAL_STATIC_LIBRARIES += libscrypt_static diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index 3120af56a1fd..8ad88eddd73b 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -17,7 +17,10 @@ #include <jni.h> #include <JNIHelp.h> +#include <hidl/HidlTransportSupport.h> + #include <sensorservice/SensorService.h> +#include <sensorservicehidl/SensorManager.h> #include <cutils/properties.h> #include <utils/Log.h> @@ -32,6 +35,21 @@ static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jo if (strcmp(propBuf, "1") == 0) { SensorService::instantiate(); } + +} + +static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) { + using ::android::frameworks::sensorservice::V1_0::ISensorManager; + using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager; + using ::android::hardware::configureRpcThreadpool; + + configureRpcThreadpool(1, false /* callerWillJoin */); + sp<ISensorManager> sensorService = new SensorManager(); + status_t err = sensorService->registerAsService(); + if (err != OK) { + ALOGE("Cannot register ::android::frameworks::sensorservice::V1_0::" + "implementation::SensorManager: %d", err); + } } /* @@ -40,6 +58,7 @@ static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jo static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }, + { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices }, }; int register_android_server_SystemServer(JNIEnv* env) diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a8423e2e8a11..e6e02428ae63 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -86,6 +86,7 @@ import com.android.server.notification.NotificationManagerService; import com.android.server.om.OverlayManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.SchedulingPolicyService; +import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.Installer; import com.android.server.pm.LauncherAppsService; import com.android.server.pm.OtaDexoptService; @@ -235,16 +236,24 @@ public final class SystemServer { private final boolean mRuntimeRestart; private static final String START_SENSOR_SERVICE = "StartSensorService"; + private static final String START_HIDL_SERVICES = "StartHidlServices"; + + private Future<?> mSensorServiceStart; private Future<?> mZygotePreload; - /** * Start the sensor service. This is a blocking call and can take time. */ private static native void startSensorService(); /** + * Start all HIDL services that are run inside the system server. This + * may take some time. + */ + private static native void startHidlServices(); + + /** * The main entry point from zygote. */ public static void main(String[] args) { @@ -610,6 +619,7 @@ public final class SystemServer { startSensorService(); traceLog.traceEnd(); }, START_SENSOR_SERVICE); + } /** @@ -637,6 +647,14 @@ public final class SystemServer { traceBeginAndSlog("StartWebViewUpdateService"); mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class); traceEnd(); + + // Start receiving calls from HIDL services. Start in in a separate thread + // because it need to connect to SensorManager. + SystemServerInitThreadPool.get().submit(() -> { + traceBeginAndSlog(START_HIDL_SERVICES); + startHidlServices(); + traceEnd(); + }, START_HIDL_SERVICES); } /** @@ -1428,11 +1446,11 @@ public final class SystemServer { traceEnd(); } - traceBeginAndSlog("StartBackgroundDexOptJobService"); + traceBeginAndSlog("StartBackgroundDexOptService"); try { - BackgroundDexOptJobService.schedule(context); + BackgroundDexOptService.schedule(context); } catch (Throwable e) { - reportWtf("starting StartBackgroundDexOptJobService", e); + reportWtf("starting StartBackgroundDexOptService", e); } traceEnd(); diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index 3e3a19b8effd..c670782b443e 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -16,6 +16,8 @@ package android.net.ip; +import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; + import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; @@ -42,6 +44,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemClock; +import android.system.OsConstants; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; @@ -1028,15 +1031,36 @@ public class IpManager extends StateMachine { return true; } - private boolean startIPv6() { - // Set privacy extensions. + private void enableInterfaceIPv6PrivacyExtensions() { final String PREFER_TEMPADDRS = "2"; - try { - NetdService.run((INetd netd) -> { + NetdService.run((INetd netd) -> { netd.setProcSysNet( - INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", - PREFER_TEMPADDRS); + INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", PREFER_TEMPADDRS); }); + } + + private void setInterfaceIPv6RaRtInfoMaxPlen(int plen) { + // Setting RIO max plen is best effort. Catch and ignore most exceptions. + try { + NetdService.run((INetd netd) -> { + netd.setProcSysNet( + INetd.IPV6, INetd.CONF, mInterfaceName, "accept_ra_rt_info_max_plen", + Integer.toString(plen)); + }); + } catch (ServiceSpecificException e) { + // Old kernel versions without support for RIOs do not export accept_ra_rt_info_max_plen + // in the /proc filesystem. If the kernel supports RIOs we should never see any other + // type of error. + if (e.errorCode != OsConstants.ENOENT) { + logError("unexpected error setting accept_ra_rt_info_max_plen %s", e); + } + } + } + + private boolean startIPv6() { + try { + enableInterfaceIPv6PrivacyExtensions(); + setInterfaceIPv6RaRtInfoMaxPlen(RFC7421_PREFIX_LENGTH); mNwService.enableIpv6(mInterfaceName); } catch (IllegalStateException|RemoteException|ServiceSpecificException e) { logError("Unable to change interface settings: %s", e); diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java index 362f7570c124..26f3050468dd 100644 --- a/services/net/java/android/net/util/NetworkConstants.java +++ b/services/net/java/android/net/util/NetworkConstants.java @@ -97,6 +97,7 @@ public final class NetworkConstants { public static final int IPV6_SRC_ADDR_OFFSET = 8; public static final int IPV6_DST_ADDR_OFFSET = 24; public static final int IPV6_ADDR_LEN = 16; + public static final int RFC7421_PREFIX_LENGTH = 64; /** * ICMPv6 constants. diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk index de9553a46eef..a5d557048232 100644 --- a/services/tests/notification/Android.mk +++ b/services/tests/notification/Android.mk @@ -30,6 +30,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_JACK_FLAGS := --multi-dex native LOCAL_PACKAGE_NAME := FrameworksNotificationTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java index 5f215f937a97..27b9a880c4ac 100644 --- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java @@ -203,7 +203,6 @@ public class RankingHelperTest { private void compareChannels(NotificationChannel expected, NotificationChannel actual) { assertEquals(expected.getId(), actual.getId()); assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getNameResId(), actual.getNameResId()); assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); assertEquals(expected.getImportance(), actual.getImportance()); @@ -219,7 +218,6 @@ public class RankingHelperTest { private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) { assertEquals(expected.getId(), actual.getId()); assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getNameResId(), actual.getNameResId()); } @Test @@ -274,15 +272,12 @@ public class RankingHelperTest { @Test public void testChannelXml() throws Exception { - int nameResId = 924896; - int groupNameResId = 426272; - - NotificationChannelGroup ncg = new NotificationChannelGroup("1", groupNameResId); + NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel2 = - new NotificationChannel("id2", nameResId, IMPORTANCE_LOW); + new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); channel2.enableLights(true); channel2.setBypassDnd(true); @@ -728,6 +723,25 @@ public class RankingHelperTest { } @Test + public void testGetDeletedChannelCount() throws Exception { + NotificationChannel channel = + new NotificationChannel("id2", "name2", IMPORTANCE_LOW); + NotificationChannel channel2 = + new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); + NotificationChannel channel3 = + new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); + mHelper.createNotificationChannel(pkg, uid, channel, true); + mHelper.createNotificationChannel(pkg, uid, channel2, true); + mHelper.createNotificationChannel(pkg, uid, channel3, true); + + mHelper.deleteNotificationChannel(pkg, uid, channel.getId()); + mHelper.deleteNotificationChannel(pkg, uid, channel3.getId()); + + assertEquals(2, mHelper.getDeletedChannelCount(pkg, uid)); + assertEquals(0, mHelper.getDeletedChannelCount(pkg2, uid2)); + } + + @Test public void testUpdateDeletedChannels() throws Exception { NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); @@ -840,6 +854,43 @@ public class RankingHelperTest { } @Test + public void testDeleteGroup() throws Exception { + NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); + NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted"); + NotificationChannel nonGroupedNonDeletedChannel = + new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH); + NotificationChannel groupedButNotDeleted = + new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); + groupedButNotDeleted.setGroup("not"); + NotificationChannel groupedAndDeleted = + new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); + groupedAndDeleted.setGroup("totally"); + + mHelper.createNotificationChannelGroup(pkg, uid, notDeleted, true); + mHelper.createNotificationChannelGroup(pkg, uid, deleted, true); + mHelper.createNotificationChannel(pkg, uid, nonGroupedNonDeletedChannel, true); + mHelper.createNotificationChannel(pkg, uid, groupedAndDeleted, true); + mHelper.createNotificationChannel(pkg, uid, groupedButNotDeleted, true); + + mHelper.deleteNotificationChannelGroup(pkg, uid, deleted.getId()); + + assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), pkg, uid)); + assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), pkg, uid)); + + assertNull(mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), false)); + compareChannels(groupedAndDeleted, + mHelper.getNotificationChannel(pkg, uid, groupedAndDeleted.getId(), true)); + + compareChannels(groupedButNotDeleted, + mHelper.getNotificationChannel(pkg, uid, groupedButNotDeleted.getId(), false)); + compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel( + pkg, uid, nonGroupedNonDeletedChannel.getId(), false)); + + // notDeleted + assertEquals(1, mHelper.getNotificationChannelGroups(pkg, uid).size()); + } + + @Test public void testOnPackageChanged_packageRemoval() throws Exception { // Deleted NotificationChannel channel1 = @@ -875,7 +926,7 @@ public class RankingHelperTest { mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); - assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size()); + assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid).size()); } @Test @@ -994,14 +1045,18 @@ public class RankingHelperTest { } @Test - public void testCreateChannel_updateNameResId() throws Exception { - NotificationChannel nc = new NotificationChannel("id", 1, IMPORTANCE_DEFAULT); + public void testCreateChannel_updateName() throws Exception { + NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); mHelper.createNotificationChannel(pkg, uid, nc, true); + NotificationChannel actual = mHelper.getNotificationChannel(pkg, uid, "id", false); + assertEquals("hello", actual.getName()); - nc = new NotificationChannel("id", 2, IMPORTANCE_DEFAULT); + nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); mHelper.createNotificationChannel(pkg, uid, nc, true); - assertEquals(2, mHelper.getNotificationChannel(pkg, uid, "id", false).getNameResId()); + actual = mHelper.getNotificationChannel(pkg, uid, "id", false); + assertEquals("goodbye", actual.getName()); + assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); } @Test diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 15c61f6f228b..2a8f4a34f158 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -30,6 +30,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksServicesTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java index c6265bc768f3..a2a4019c93ad 100644 --- a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java @@ -25,6 +25,8 @@ import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.pm.UserInfo; import android.database.sqlite.SQLiteDatabase; @@ -76,7 +78,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { UserManager mUserManager; MockStorageManager mStorageManager; IActivityManager mActivityManager; - + DevicePolicyManager mDevicePolicyManager; KeyStore mKeyStore; @Override @@ -89,7 +91,9 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { mUserManager = mock(UserManager.class); mStorageManager = new MockStorageManager(); mActivityManager = mock(IActivityManager.class); - mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager); + mDevicePolicyManager = mock(DevicePolicyManager.class); + mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, + mDevicePolicyManager); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; @@ -122,6 +126,10 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { }); when(mLockPatternUtils.getLockSettings()).thenReturn(mService); + + // Adding a fake Device Owner app which will enable escrow token support in LSS. + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( + new ComponentName("com.dummy.package", ".FakeDeviceOwner")); } @Override diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java index c68fbdc0a2ac..46779048e9db 100644 --- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.UserInfo; @@ -68,7 +69,7 @@ public class LockSettingsStorageTests extends AndroidTestCase { when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0)); MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager, - mock(NotificationManager.class)); + mock(NotificationManager.class), mock(DevicePolicyManager.class)); mStorage = new LockSettingsStorageTestable(context, new File(getContext().getFilesDir(), "locksettings")); mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() { diff --git a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java index b63936fdffdf..8bceed45ab5f 100644 --- a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java +++ b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java @@ -17,6 +17,7 @@ package com.android.server; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.ContextWrapper; import android.os.UserManager; @@ -25,12 +26,14 @@ public class MockLockSettingsContext extends ContextWrapper { private UserManager mUserManager; private NotificationManager mNotificationManager; + private DevicePolicyManager mDevicePolicyManager; public MockLockSettingsContext(Context base, UserManager userManager, - NotificationManager notificationManager) { + NotificationManager notificationManager, DevicePolicyManager devicePolicyManager) { super(base); mUserManager = userManager; mNotificationManager = notificationManager; + mDevicePolicyManager = devicePolicyManager; } @Override @@ -39,6 +42,8 @@ public class MockLockSettingsContext extends ContextWrapper { return mUserManager; } else if (NOTIFICATION_SERVICE.equals(name)) { return mNotificationManager; + } else if (DEVICE_POLICY_SERVICE.equals(name)) { + return mDevicePolicyManager; } else { throw new RuntimeException("System service not mocked: " + name); } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 9f50a2c30aae..921e0e3deeb4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -126,8 +126,6 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test - @Ignore - // TODO(b/35034729): Need to fix before re-enabling public void testLandscapeSeascapeRotationByPolicy() throws Exception { // Some plumbing to get the service ready for rotation updates. sWm.mDisplayReady = true; @@ -145,15 +143,20 @@ public class AppWindowTokenTests extends WindowTestsBase { appWindowToken.addWindow(appWindow); // Set initial orientation and update. - ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_90; - sWm.updateRotation(false, false); + performRotation(Surface.ROTATION_90); appWindow.resizeReported = false; // Update the rotation to perform 180 degree rotation and check that resize was reported. - ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_270; - sWm.updateRotation(false, false); - sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); + performRotation(Surface.ROTATION_270); assertTrue(appWindow.resizeReported); appWindow.removeImmediately(); } + + private void performRotation(int rotationToReport) { + ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = rotationToReport; + sWm.updateRotation(false, false); + // Simulate animator finishing orientation change + sWm.mRoot.mOrientationChangeComplete = true; + sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java index b6dc9a5b6e34..0a644b60d224 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java @@ -18,11 +18,11 @@ package com.android.server.wm; import com.android.internal.os.IResultReceiver; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.MergedConfiguration; import android.view.DragEvent; import android.view.IWindow; @@ -36,7 +36,7 @@ public class TestIWindow extends IWindow.Stub { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, - Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig, + Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index 911050a27a83..65efd9cd23ae 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -71,7 +71,10 @@ class WindowTestsBase { static TestWindowManagerPolicy sPolicy = null; private final static IWindow sIWindow = new TestIWindow(); private final static Session sMockSession = mock(Session.class); - private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1; + // The default display is removed in {@link #setUp} and then we iterate over all displays to + // make sure we don't collide with any existing display. If we run into no other display, the + // added display should be treated as default. + private static int sNextDisplayId = Display.DEFAULT_DISPLAY; static int sNextStackId = FIRST_DYNAMIC_STACK_ID; private static int sNextTaskId = 0; diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 40bdaa58a864..03d82412a5c5 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -25,8 +25,8 @@ import android.hardware.usb.UsbInterface; import android.media.AudioSystem; import android.media.IAudioService; import android.media.midi.MidiDeviceInfo; -import android.os.FileObserver; import android.os.Bundle; +import android.os.FileObserver; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -41,10 +41,7 @@ import com.android.server.audio.AudioService; import libcore.io.IoUtils; import java.io.File; -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.HashMap; -import java.util.ArrayList; /** * UsbAlsaManager manages USB audio and MIDI devices. @@ -219,23 +216,23 @@ public final class UsbAlsaManager { AlsaDevice testDevice = new AlsaDevice(type, card, device); // This value was empirically determined. - final int kWaitTime = 2500; // ms + final int kWaitTimeMs = 2500; synchronized(mAlsaDevices) { - long timeout = SystemClock.elapsedRealtime() + kWaitTime; + long timeoutMs = SystemClock.elapsedRealtime() + kWaitTimeMs; do { if (mAlsaDevices.values().contains(testDevice)) { return testDevice; } - long waitTime = timeout - SystemClock.elapsedRealtime(); - if (waitTime > 0) { + long waitTimeMs = timeoutMs - SystemClock.elapsedRealtime(); + if (waitTimeMs > 0) { try { - mAlsaDevices.wait(waitTime); + mAlsaDevices.wait(waitTimeMs); } catch (InterruptedException e) { Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file."); } } - } while (timeout > SystemClock.elapsedRealtime()); + } while (timeoutMs > SystemClock.elapsedRealtime()); } Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice); @@ -498,6 +495,7 @@ public final class UsbAlsaManager { // Devices List // /* + //import java.util.ArrayList; public ArrayList<UsbAudioDevice> getConnectedDevices() { ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size()); for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) { diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java index 808b5d39b44e..a7bdabd64684 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java @@ -138,7 +138,7 @@ public class ColorFiltersMutateActivity extends Activity { mSaturation = saturation; final ColorMatrixColorFilter filter = (ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter(); - final ColorMatrix m = filter.getColorMatrix(); + final ColorMatrix m = new ColorMatrix(); m.setSaturation(saturation); filter.setColorMatrix(m); invalidate(); diff --git a/tests/net/Android.mk b/tests/net/Android.mk index 79f6e4d2f000..504d54eeb3a9 100644 --- a/tests/net/Android.mk +++ b/tests/net/Android.mk @@ -24,6 +24,7 @@ LOCAL_JAVA_LIBRARIES := \ android.test.runner LOCAL_PACKAGE_NAME := FrameworksNetTests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk index 58399fd5bc6c..759bc3555fa1 100644 --- a/tests/testables/Android.mk +++ b/tests/testables/Android.mk @@ -25,7 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ - mockito-updated-target-minus-junit4 \ + mockito-target-minus-junit4 \ legacy-android-test LOCAL_JAVA_LIBRARIES := android.test.runner diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk index 752d536ae4c6..a123d801ed5a 100644 --- a/tests/testables/tests/Android.mk +++ b/tests/testables/tests/Android.mk @@ -27,7 +27,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ - mockito-updated-target-minus-junit4 \ + mockito-target-minus-junit4 \ legacy-android-test \ testables diff --git a/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java index b1e71b241f14..cc71053fced6 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java @@ -24,6 +24,7 @@ import com.android.layoutlib.bridge.impl.PorterDuffUtility; import com.android.ninepatch.NinePatchChunk; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import android.annotation.Nullable; import android.text.TextUtils; import java.awt.*; @@ -31,6 +32,8 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; public class BaseCanvas_Delegate { // ---- delegate manager ---- @@ -646,9 +649,15 @@ public class BaseCanvas_Delegate { forceSrcMode[0] = false; // if the bitmap config is alpha_8, then we erase all color value from it - // before drawing it. + // before drawing it or apply the texture from the shader if present. if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) { - fixAlpha8Bitmap(image); + Shader_Delegate shader = paint.getShader(); + java.awt.Paint javaPaint = null; + if (shader instanceof BitmapShader_Delegate) { + javaPaint = shader.getJavaPaint(); + } + + fixAlpha8Bitmap(image, javaPaint); } else if (!bitmap.hasAlpha()) { // hasAlpha is merely a rendering hint. There can in fact be alpha values // in the bitmap but it should be ignored at drawing time. @@ -672,16 +681,37 @@ public class BaseCanvas_Delegate { return image; } - private static void fixAlpha8Bitmap(final BufferedImage image) { + /** + * This method will apply the correct color to the passed "only alpha" image. Colors on the + * passed image will be destroyed. + * If the passed javaPaint is null, the color will be set to 0. If a paint is passed, it will + * be used to obtain the color that will be applied. + * <p/> + * This will destroy the passed image color channel. + */ + private static void fixAlpha8Bitmap(final BufferedImage image, + @Nullable java.awt.Paint javaPaint) { int w = image.getWidth(); int h = image.getHeight(); + + DataBuffer texture = null; + if (javaPaint != null) { + PaintContext context = javaPaint.createContext(ColorModel.getRGBdefault(), null, null, + new AffineTransform(), null); + texture = context.getRaster(0, 0, w, h).getDataBuffer(); + } + int[] argb = new int[w * h]; image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); final int length = argb.length; - for (int i = 0 ; i < length; i++) { + for (int i = 0; i < length; i++) { argb[i] &= 0xFF000000; + if (texture != null) { + argb[i] |= texture.getElem(i) & 0x00FFFFFF; + } } + image.setRGB(0, 0, w, h, argb, 0, w); } diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java index bd934d028aff..cb013b60a06c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java @@ -66,7 +66,7 @@ public abstract class ColorFilter_Delegate { // ---- native methods ---- @LayoutlibDelegate - /*package*/ static void destroyFilter(long native_instance) { + /*package*/ static void nSafeUnref(long native_instance) { sManager.removeJavaReferenceFor(native_instance); } diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index ff5a5e9541df..aaff5d594920 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -16,7 +16,6 @@ package android.graphics; -import android.text.FontConfig; import com.android.ide.common.rendering.api.AssetRepository; import com.android.ide.common.rendering.api.LayoutLog; import com.android.layoutlib.bridge.Bridge; @@ -293,12 +292,16 @@ public class FontFamily_Delegate { @LayoutlibDelegate /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font, - int ttcIndex, List<FontConfig.Axis> listOfAxis, - int weight, boolean isItalic) { + int ttcIndex, int weight, boolean isItalic) { assert false : "The only client of this method has been overriden."; return false; } + @LayoutlibDelegate + /*package*/ static void nAddAxisValue(long builderPtr, int tag, float value) { + assert false : "The only client of this method has been overriden."; + } + static boolean addFont(long builderPtr, final String path, final int weight, final boolean isItalic) { final FontFamily_Delegate delegate = getDelegate(builderPtr); diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index aa1f00dee42e..1bb56e3be415 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -964,8 +964,9 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text, - int contextStart, int contextLength, int flags, int offset, int cursorOpt) { + /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr, + char[] text, int contextStart, int contextLength, int flags, int offset, + int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "Paint.getTextRunCursor is not supported.", null, null /*data*/); @@ -973,8 +974,8 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text, - int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { + /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, long typefacePtr, + String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "Paint.getTextRunCursor is not supported.", null, null /*data*/); diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java deleted file mode 100644 index 7e9432dd71ef..000000000000 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/AdaptiveIconDrawable_Delegate.java +++ /dev/null @@ -1,59 +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 android.graphics.drawable; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.drawable.AdaptiveIconDrawable.LayerState; - -/** - * Delegate used to provide new implementation of a select few methods of {@link - * AdaptiveIconDrawable} - * <p> - * Through the layoutlib_create tool, the original methods of AdaptiveIconDrawable have been - * replaced by calls to methods of the same name in this delegate class. - */ -@SuppressWarnings("unused") -public class AdaptiveIconDrawable_Delegate { - @LayoutlibDelegate - /*package*/ static void draw(AdaptiveIconDrawable thisDrawable, Canvas canvas) { - // This is a workaround for the broken BitmapShader in layoutlib. This new draw methods - // avoids the use of the shader. - - for (int i = 0; i < LayerState.N_CHILDREN; i++) { - if (thisDrawable.mLayerState.mChildren[i] == null) { - continue; - } - final Drawable dr = thisDrawable.mLayerState.mChildren[i].mDrawable; - if (dr != null) { - dr.draw(canvas); - } - } - - if (thisDrawable.mMaskBitmap != null) { - Rect bounds = thisDrawable.getBounds(); - Paint paint = new Paint(); - paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); - canvas.drawBitmap(thisDrawable.mMaskBitmap, bounds.left, bounds.top, paint); - } - } -} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java index 468949117635..ffbe7c43ceab 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java @@ -18,12 +18,12 @@ package com.android.layoutlib.bridge.android; import com.android.internal.os.IResultReceiver; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.MergedConfiguration; import android.view.DragEvent; import android.view.IWindow; @@ -50,7 +50,7 @@ public final class BridgeWindow implements IWindow { @Override public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6, - boolean b, Configuration configuration, Rect rect7, boolean b2, boolean b3, int i0) + boolean b, MergedConfiguration mergedConfig, Rect rect7, boolean b2, boolean b3, int i0) throws RemoteException { // pass for now. } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index 4dfe47be0ef6..2c883940510e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -17,12 +17,12 @@ package com.android.layoutlib.bridge.android; import android.content.ClipData; -import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.MergedConfiguration; import android.view.IWindow; import android.view.IWindowId; import android.view.IWindowSession; @@ -89,7 +89,7 @@ public final class BridgeWindowSession implements IWindowSession { @Override public int relayout(IWindow iWindow, int i, LayoutParams layoutParams, int i2, int i3, int i4, int i5, Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, - Rect rect6, Rect rect7, Configuration configuration, Surface surface) + Rect rect6, Rect rect7, MergedConfiguration mergedConfig, Surface surface) throws RemoteException { // pass for now. return 0; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 4f226cbad01f..b0aa3c2989a5 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -163,7 +163,6 @@ public final class CreateInfo implements ICreateInfo { "android.content.res.TypedArray#obtain", "android.graphics.BitmapFactory#finishDecode", "android.graphics.BitmapFactory#setDensityFromOptions", - "android.graphics.drawable.AdaptiveIconDrawable#draw", "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget", "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#onDraw", "android.graphics.drawable.GradientDrawable#buildRing", @@ -333,8 +332,6 @@ public final class CreateInfo implements ICreateInfo { * needed when access from the delegate classes is needed. */ private final static String[] PROMOTED_FIELDS = new String[] { - "android.graphics.drawable.AdaptiveIconDrawable#mMaskBitmap", - "android.graphics.drawable.AdaptiveIconDrawable#mPaint", "android.graphics.drawable.VectorDrawable#mVectorState", "android.view.Choreographer#mLastFrameTimeNanos", "android.graphics.FontFamily#mBuilderPtr" diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index a1099f8045c5..04f9059fb544 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -281,7 +281,9 @@ public class WifiConfiguration implements Parcelable { public int apChannel = 0; /** - * Pre-shared key for use with WPA-PSK. + * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in + * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or + * a string of 64 hex digits for raw PSK. * <p/> * When the value of this key is read, the actual key is * not returned, just a "*" if the key has a value, or the null @@ -305,7 +307,7 @@ public class WifiConfiguration implements Parcelable { /** * Priority determines the preference given to a network by {@code wpa_supplicant} * when choosing an access point with which to associate. - * @deprecated Priority is no longer used. + * @deprecated This field does not exist anymore. */ @Deprecated public int priority; @@ -434,6 +436,13 @@ public class WifiConfiguration implements Parcelable { public int dtimInterval = 0; /** + * Flag indicating if this configuration represents a legacy Passpoint configuration + * (Release N or older). This is used for migrating Passpoint configuration from N to O. + * This will no longer be needed after O. + * @hide + */ + public boolean isLegacyPasspointConfig = false; + /** * @hide * Uid of app creating the configuration */ @@ -1961,6 +1970,7 @@ public class WifiConfiguration implements Parcelable { mCachedConfigKey = null; //force null configKey selfAdded = source.selfAdded; validatedInternetAccess = source.validatedInternetAccess; + isLegacyPasspointConfig = source.isLegacyPasspointConfig; ephemeral = source.ephemeral; meteredHint = source.meteredHint; meteredOverride = source.meteredOverride; @@ -2037,6 +2047,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(selfAdded ? 1 : 0); dest.writeInt(didSelfAdd ? 1 : 0); dest.writeInt(validatedInternetAccess ? 1 : 0); + dest.writeInt(isLegacyPasspointConfig ? 1 : 0); dest.writeInt(ephemeral ? 1 : 0); dest.writeInt(meteredHint ? 1 : 0); dest.writeInt(meteredOverride ? 1 : 0); @@ -2103,6 +2114,7 @@ public class WifiConfiguration implements Parcelable { config.selfAdded = in.readInt() != 0; config.didSelfAdd = in.readInt() != 0; config.validatedInternetAccess = in.readInt() != 0; + config.isLegacyPasspointConfig = in.readInt() != 0; config.ephemeral = in.readInt() != 0; config.meteredHint = in.readInt() != 0; config.meteredOverride = in.readInt() != 0; diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk index eac49d20b88d..8dc244f086cc 100644 --- a/wifi/tests/Android.mk +++ b/wifi/tests/Android.mk @@ -58,5 +58,6 @@ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ LOCAL_PACKAGE_NAME := FrameworksWifiApiTests +LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) |