diff options
202 files changed, 2590 insertions, 2269 deletions
diff --git a/api/current.txt b/api/current.txt index af842b5c76bc..eb244e4cd1eb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -224,6 +224,7 @@ package android { field public static final int __removed3 = 16844187; // 0x101059b field public static final int __removed4 = 16844188; // 0x101059c field public static final int __removed5 = 16844189; // 0x101059d + field public static final int __removed6 = 16844182; // 0x1010596 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -750,7 +751,6 @@ package android { field public static final int immersive = 16843456; // 0x10102c0 field public static final int importantForAccessibility = 16843690; // 0x10103aa field public static final int importantForAutofill = 16844120; // 0x1010558 - field public static final int importantForContentCapture = 16844182; // 0x1010596 field public static final int inAnimation = 16843127; // 0x1010177 field public static final int includeFontPadding = 16843103; // 0x101015f field public static final int includeInGlobalSearch = 16843374; // 0x101026e @@ -6235,14 +6235,14 @@ package android.app { } public class TaskInfo { - field public android.content.ComponentName baseActivity; - field public android.content.Intent baseIntent; + field @Nullable public android.content.ComponentName baseActivity; + field @NonNull public android.content.Intent baseIntent; field public boolean isRunning; field public int numActivities; - field public android.content.ComponentName origActivity; - field public android.app.ActivityManager.TaskDescription taskDescription; + field @Nullable public android.content.ComponentName origActivity; + field @Nullable public android.app.ActivityManager.TaskDescription taskDescription; field public int taskId; - field public android.content.ComponentName topActivity; + field @Nullable public android.content.ComponentName topActivity; } public class TaskStackBuilder { @@ -9001,7 +9001,7 @@ package android.bluetooth.le { method @Nullable public byte[] getManufacturerSpecificData(int); method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData(); method @Nullable public byte[] getServiceData(android.os.ParcelUuid); - method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); + method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public int getTxPowerLevel(); } @@ -23045,6 +23045,7 @@ package android.media { public final class AudioAttributes implements android.os.Parcelable { method public boolean areHapticChannelsMuted(); method public int describeContents(); + method public int getAllowedCapturePolicy(); method public int getContentType(); method public int getFlags(); method public int getUsage(); @@ -23250,6 +23251,7 @@ package android.media { method public int generateAudioSessionId(); method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations(); method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations(); + method public int getAllowedCapturePolicy(); method public android.media.AudioDeviceInfo[] getDevices(int); method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException; method public int getMode(); @@ -23422,6 +23424,10 @@ package android.media { } public final class AudioPlaybackCaptureConfiguration { + method @NonNull public int[] getExcludeUids(); + method @NonNull public int[] getExcludeUsages(); + method @NonNull public int[] getMatchingUids(); + method @NonNull public int[] getMatchingUsages(); method @NonNull public android.media.projection.MediaProjection getMediaProjection(); } @@ -25132,25 +25138,6 @@ package android.media { field public static final int TYPE_STRING = 4; // 0x4 } - public final class MediaItem2 implements android.os.Parcelable { - method public int describeContents(); - method public long getEndPosition(); - method @Nullable public android.media.MediaMetadata getMetadata(); - method public long getStartPosition(); - method public void setMetadata(@Nullable android.media.MediaMetadata); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.media.MediaItem2> CREATOR; - field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL - } - - public static final class MediaItem2.Builder { - ctor public MediaItem2.Builder(); - method @NonNull public android.media.MediaItem2 build(); - method @NonNull public android.media.MediaItem2.Builder setEndPosition(long); - method @NonNull public android.media.MediaItem2.Builder setMetadata(@Nullable android.media.MediaMetadata); - method @NonNull public android.media.MediaItem2.Builder setStartPosition(long); - } - public final class MediaMetadata implements android.os.Parcelable { method public boolean containsKey(String); method public int describeContents(); @@ -26171,8 +26158,8 @@ package android.media { ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle); method public int describeContents(); method public int getCommandCode(); - method @Nullable public String getCustomCommand(); - method @Nullable public android.os.Bundle getExtras(); + method @Nullable public String getCustomAction(); + method @Nullable public android.os.Bundle getCustomExtras(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0 field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR; @@ -38619,6 +38606,7 @@ package android.provider { field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"; field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"; field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"; + field public static final String ACTION_APP_BATTERY_SETTINGS = "android.settings.APP_BATTERY_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS"; @@ -39090,7 +39078,7 @@ package android.provider { field @Deprecated public static final String BEARER = "bearer"; field public static final String CARRIER_ENABLED = "carrier_enabled"; field public static final String CARRIER_ID = "carrier_id"; - field public static final android.net.Uri CONTENT_URI; + field @NonNull public static final android.net.Uri CONTENT_URI; field public static final String CURRENT = "current"; field public static final String DEFAULT_SORT_ORDER = "name ASC"; field @Deprecated public static final String MCC = "mcc"; @@ -39109,7 +39097,7 @@ package android.provider { field public static final String PROXY = "proxy"; field public static final String ROAMING_PROTOCOL = "roaming_protocol"; field public static final String SERVER = "server"; - field public static final android.net.Uri SIM_APN_URI; + field @NonNull public static final android.net.Uri SIM_APN_URI; field public static final String SUBSCRIPTION_ID = "sub_id"; field public static final String TYPE = "type"; field public static final String USER = "user"; @@ -47812,6 +47800,10 @@ package android.util { method public boolean equals(android.util.DisplayMetrics); method public void setTo(android.util.DisplayMetrics); method public void setToDefaults(); + field public static final int DENSITY_140 = 140; // 0x8c + field public static final int DENSITY_180 = 180; // 0xb4 + field public static final int DENSITY_200 = 200; // 0xc8 + field public static final int DENSITY_220 = 220; // 0xdc field public static final int DENSITY_260 = 260; // 0x104 field public static final int DENSITY_280 = 280; // 0x118 field public static final int DENSITY_300 = 300; // 0x12c @@ -50195,7 +50187,6 @@ package android.view { method @android.view.ViewDebug.CapturedViewProperty @IdRes public int getId(); method @android.view.ViewDebug.ExportedProperty(category="accessibility", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to="noHideDescendants")}) public int getImportantForAccessibility(); method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForAutofill(); - method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForContentCapture(); method public boolean getKeepScreenOn(); method public android.view.KeyEvent.DispatcherState getKeyDispatcherState(); method @android.view.ViewDebug.ExportedProperty(category="accessibility") @IdRes public int getLabelFor(); @@ -50336,7 +50327,6 @@ package android.view { method @android.view.ViewDebug.ExportedProperty public boolean isHovered(); method public boolean isImportantForAccessibility(); method public final boolean isImportantForAutofill(); - method public final boolean isImportantForContentCapture(); method public boolean isInEditMode(); method public boolean isInLayout(); method @android.view.ViewDebug.ExportedProperty public boolean isInTouchMode(); @@ -50411,7 +50401,6 @@ package android.view { method @CallSuper public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); method public void onProvideAutofillStructure(android.view.ViewStructure, int); method public void onProvideAutofillVirtualStructure(android.view.ViewStructure, int); - method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int); method public void onProvideStructure(android.view.ViewStructure); method public void onProvideVirtualStructure(android.view.ViewStructure); method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int); @@ -50537,7 +50526,6 @@ package android.view { method public void setId(@IdRes int); method public void setImportantForAccessibility(int); method public void setImportantForAutofill(int); - method public void setImportantForContentCapture(int); method public void setKeepScreenOn(boolean); method public void setKeyboardNavigationCluster(boolean); method public void setLabelFor(@IdRes int); @@ -50716,11 +50704,6 @@ package android.view { field public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 field public static final int IMPORTANT_FOR_AUTOFILL_YES = 1; // 0x1 field public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0; // 0x0 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 2; // 0x2 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 8; // 0x8 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 1; // 0x1 - field public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 4; // 0x4 field public static final int INVISIBLE = 4; // 0x4 field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000 field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2 @@ -52828,7 +52811,7 @@ package android.view.contentcapture { method @Nullable public java.util.Set<android.view.contentcapture.ContentCaptureCondition> getContentCaptureConditions(); method @Nullable public android.content.ComponentName getServiceComponentName(); method public boolean isContentCaptureEnabled(); - method public void removeUserData(@NonNull android.view.contentcapture.UserDataRemovalRequest); + method public void removeData(@NonNull android.view.contentcapture.DataRemovalRequest); method public void setContentCaptureEnabled(boolean); } @@ -52839,6 +52822,7 @@ package android.view.contentcapture { method @Nullable public final android.view.contentcapture.ContentCaptureContext getContentCaptureContext(); method @NonNull public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId(); method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long); + method @NonNull public final android.view.ViewStructure newViewStructure(@NonNull android.view.View); method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long); method public final void notifyViewAppeared(@NonNull android.view.ViewStructure); method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId); @@ -52853,24 +52837,24 @@ package android.view.contentcapture { field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureSessionId> CREATOR; } - public final class UserDataRemovalRequest implements android.os.Parcelable { + public final class DataRemovalRequest implements android.os.Parcelable { method public int describeContents(); - method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.LocusIdRequest> getLocusIdRequests(); + method @NonNull public java.util.List<android.view.contentcapture.DataRemovalRequest.LocusIdRequest> getLocusIdRequests(); method @NonNull public String getPackageName(); method public boolean isForEverything(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.UserDataRemovalRequest> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.DataRemovalRequest> CREATOR; field public static final int FLAG_IS_PREFIX = 1; // 0x1 } - public static final class UserDataRemovalRequest.Builder { - ctor public UserDataRemovalRequest.Builder(); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder addLocusId(@NonNull android.content.LocusId, int); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest build(); - method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder forEverything(); + public static final class DataRemovalRequest.Builder { + ctor public DataRemovalRequest.Builder(); + method @NonNull public android.view.contentcapture.DataRemovalRequest.Builder addLocusId(@NonNull android.content.LocusId, int); + method @NonNull public android.view.contentcapture.DataRemovalRequest build(); + method @NonNull public android.view.contentcapture.DataRemovalRequest.Builder forEverything(); } - public final class UserDataRemovalRequest.LocusIdRequest { + public final class DataRemovalRequest.LocusIdRequest { method @NonNull public int getFlags(); method @NonNull public android.content.LocusId getLocusId(); } @@ -53420,6 +53404,7 @@ package android.view.textclassifier { method public int describeContents(); method @Nullable public String getCallingPackageName(); method @NonNull public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation(); + method @NonNull public android.os.Bundle getExtras(); method @Nullable public java.util.List<java.lang.String> getHints(); method @IntRange(from=0xffffffff) public int getMaxSuggestions(); method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig(); @@ -53432,6 +53417,7 @@ package android.view.textclassifier { public static final class ConversationActions.Request.Builder { ctor public ConversationActions.Request.Builder(@NonNull java.util.List<android.view.textclassifier.ConversationActions.Message>); method @NonNull public android.view.textclassifier.ConversationActions.Request build(); + method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setExtras(@Nullable android.os.Bundle); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setHints(@Nullable java.util.List<java.lang.String>); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(@IntRange(from=0xffffffff) int); method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig); diff --git a/api/system-current.txt b/api/system-current.txt index 2d8b09293abb..d15d00682817 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1092,12 +1092,11 @@ package android.app.prediction { } public static final class AppTarget.Builder { - ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo); method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -2002,15 +2001,15 @@ package android.hardware.hdmi { public final class HdmiControlManager { method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); method @Nullable public android.hardware.hdmi.HdmiClient getClient(int); - method @Nullable public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList(); + method @NonNull public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevices(); method public int getPhysicalAddress(); method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient(); method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient(); method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient(); - method public boolean isRemoteDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); - method public void powerOffRemoteDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public boolean isDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public void powerOffDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); - method public void requestRemoteDeviceToBecomeActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean); field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE"; field public static final int AVR_VOLUME_MUTED = 101; // 0x65 @@ -3672,7 +3671,6 @@ package android.media.audiopolicy { method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); - method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean); method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; } @@ -5823,7 +5821,6 @@ package android.provider { public final class DeviceConfig { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int); @@ -5831,7 +5828,6 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; @@ -5864,10 +5860,6 @@ package android.provider { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } - public static interface DeviceConfig.OnPropertyChangedListener { - method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -6275,7 +6267,6 @@ package android.service.attention { public abstract class AttentionService extends android.app.Service { ctor public AttentionService(); - method public final void disableSelf(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onCancelAttentionCheck(@NonNull android.service.attention.AttentionService.AttentionCallback); method public abstract void onCheckAttention(@NonNull android.service.attention.AttentionService.AttentionCallback); @@ -6396,9 +6387,9 @@ package android.service.contentcapture { method public void onConnected(); method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent); method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId); + method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest); method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); - method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; @@ -6498,7 +6489,7 @@ package android.service.euicc { ctor public EuiccService(); method @CallSuper public android.os.IBinder onBind(android.content.Intent); method public abstract int onDeleteSubscription(int, String); - method public abstract android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle); + method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle); method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean); method public abstract int onEraseSubscriptions(int); method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean); diff --git a/api/system-removed.txt b/api/system-removed.txt index 162f212a787e..8f7112266457 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -60,6 +60,18 @@ package android.content { } +package android.hardware.hdmi { + + public final class HdmiControlManager { + method @Deprecated public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList(); + method @Deprecated public boolean isRemoteDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void powerOffRemoteDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void powerOnRemoteDevice(android.hardware.hdmi.HdmiDeviceInfo); + method @Deprecated public void requestRemoteDeviceToBecomeActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo); + } + +} + package android.location { public class LocationManager { @@ -113,6 +125,19 @@ package android.os { } +package android.provider { + + public final class DeviceConfig { + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + } + + public static interface DeviceConfig.OnPropertyChangedListener { + method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); + } + +} + package android.service.notification { public abstract class NotificationListenerService extends android.app.Service { diff --git a/api/test-current.txt b/api/test-current.txt index 6fb4a92d7816..811ad43b5a9e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -498,12 +498,11 @@ package android.app.prediction { } public static final class AppTarget.Builder { - ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle); + ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo); method @NonNull public android.app.prediction.AppTarget build(); method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String); method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle); - method @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo); } public final class AppTargetEvent implements android.os.Parcelable { @@ -1074,6 +1073,19 @@ package android.location { package android.media { + public final class AudioFocusInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.media.AudioAttributes getAttributes(); + method @NonNull public String getClientId(); + method public int getClientUid(); + method public int getFlags(); + method public int getGainRequest(); + method public int getLossReceived(); + method @NonNull public String getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR; + } + public final class AudioFocusRequest { method @Nullable public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener(); } @@ -1085,6 +1097,15 @@ package android.media { method public static boolean isEncodingLinearPcm(int); } + public class AudioManager { + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method public boolean hasRegisteredDynamicPolicy(); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); + } + public static final class AudioRecord.MetricsConstants { field public static final String ATTRIBUTES = "android.media.audiorecord.attributes"; field public static final String CHANNEL_MASK = "android.media.audiorecord.channelMask"; @@ -1178,6 +1199,91 @@ package android.media.audiofx { } +package android.media.audiopolicy { + + public class AudioMix { + method public int getMixState(); + field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff + field public static final int MIX_STATE_IDLE = 0; // 0x0 + field public static final int MIX_STATE_MIXING = 1; // 0x1 + field public static final int ROUTE_FLAG_LOOP_BACK = 2; // 0x2 + field public static final int ROUTE_FLAG_RENDER = 1; // 0x1 + } + + public static class AudioMix.Builder { + ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException; + } + + public class AudioMixingRule { + field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2 + field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1 + field public static final int RULE_MATCH_UID = 4; // 0x4 + } + + public static class AudioMixingRule.Builder { + ctor public AudioMixingRule.Builder(); + method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, Object) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder allowPrivilegedPlaybackCapture(boolean); + method public android.media.audiopolicy.AudioMixingRule build(); + method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException; + method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException; + } + + public class AudioPolicy { + method public int attachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>); + method public android.media.AudioRecord createAudioRecordSink(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>); + method public int getFocusDuckingBehavior(); + method public int getStatus(); + method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException; + method public void setRegistration(String); + method public String toLogFriendlyString(); + field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0 + field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0 + field public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; // 0x1 + field public static final int POLICY_STATUS_REGISTERED = 2; // 0x2 + field public static final int POLICY_STATUS_UNREGISTERED = 1; // 0x1 + } + + public abstract static class AudioPolicy.AudioPolicyFocusListener { + ctor public AudioPolicy.AudioPolicyFocusListener(); + method public void onAudioFocusAbandon(android.media.AudioFocusInfo); + method public void onAudioFocusGrant(android.media.AudioFocusInfo, int); + method public void onAudioFocusLoss(android.media.AudioFocusInfo, boolean); + method public void onAudioFocusRequest(android.media.AudioFocusInfo, int); + } + + public abstract static class AudioPolicy.AudioPolicyStatusListener { + ctor public AudioPolicy.AudioPolicyStatusListener(); + method public void onMixStateUpdate(android.media.audiopolicy.AudioMix); + method public void onStatusChange(); + } + + public abstract static class AudioPolicy.AudioPolicyVolumeCallback { + ctor public AudioPolicy.AudioPolicyVolumeCallback(); + method public void onVolumeAdjustment(int); + } + + public static class AudioPolicy.Builder { + ctor public AudioPolicy.Builder(android.content.Context); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioPolicy build(); + method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener); + method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; + } + +} + package android.metrics { public class LogMaker { @@ -2106,7 +2212,6 @@ package android.provider { public final class DeviceConfig { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(@NonNull String, @NonNull String, boolean); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int); @@ -2114,7 +2219,6 @@ package android.provider { method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String); method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); - method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; @@ -2128,10 +2232,6 @@ package android.provider { method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties); } - public static interface DeviceConfig.OnPropertyChangedListener { - method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -2445,9 +2545,9 @@ package android.service.contentcapture { method public void onConnected(); method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent); method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId); + method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest); method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); - method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest); method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>); method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>); field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService"; diff --git a/api/test-removed.txt b/api/test-removed.txt index d802177e249b..83a5708a2eb3 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -1 +1,14 @@ // Signature format: 2.0 +package android.provider { + + public final class DeviceConfig { + method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener); + } + + public static interface DeviceConfig.OnPropertyChangedListener { + method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); + } + +} + diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index 47617e045c12..bb8d92737563 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -16,6 +16,7 @@ #include <sys/stat.h> // umask #include <sys/types.h> // umask + #include <fstream> #include <memory> #include <ostream> diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp index 677c6fa155dd..b7ae9d090cee 100644 --- a/cmds/idmap2/idmap2/Lookup.cpp +++ b/cmds/idmap2/idmap2/Lookup.cpp @@ -31,15 +31,14 @@ #include "androidfw/ResourceUtils.h" #include "androidfw/StringPiece.h" #include "androidfw/Util.h" -#include "utils/String16.h" -#include "utils/String8.h" - #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" +#include "utils/String16.h" +#include "utils/String8.h" using android::ApkAssets; using android::ApkAssetsCookie; diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index d8867fe8f497..87949085cf1d 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -23,12 +23,11 @@ #include <string> #include <vector> +#include "Commands.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" -#include "Commands.h" - using android::idmap2::CommandLineOptions; using android::idmap2::Result; using android::idmap2::Unit; diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index 55b1003c38af..fa9a77aa69c6 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -15,6 +15,7 @@ */ #include <dirent.h> + #include <fstream> #include <memory> #include <ostream> @@ -24,8 +25,8 @@ #include <utility> #include <vector> +#include "Commands.h" #include "android-base/properties.h" - #include "idmap2/CommandLineOptions.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" @@ -35,8 +36,6 @@ #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" -#include "Commands.h" - using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; @@ -211,7 +210,9 @@ Result<Unit> Scan(const std::vector<std::string>& args) { const auto create_ok = Create(create_args); if (!create_ok) { - return Error(create_ok.GetError(), "failed to create idmap"); + LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path + << "\": " << create_ok.GetError().GetMessage(); + continue; } } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 4f653796ce3f..8ee79f61520a 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2d/Idmap2Service.h" + #include <sys/stat.h> // umask #include <sys/types.h> // umask #include <unistd.h> @@ -28,15 +30,12 @@ #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "binder/IPCThreadState.h" -#include "utils/String8.h" - #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/SysTrace.h" - -#include "idmap2d/Idmap2Service.h" +#include "utils/String8.h" using android::IPCThreadState; using android::binder::Status; diff --git a/cmds/idmap2/idmap2d/Main.cpp b/cmds/idmap2/idmap2d/Main.cpp index 4393dcc130ec..2707049fa677 100644 --- a/cmds/idmap2/idmap2d/Main.cpp +++ b/cmds/idmap2/idmap2d/Main.cpp @@ -21,13 +21,11 @@ #include <binder/ProcessState.h> #include <cstdlib> // EXIT_{FAILURE,SUCCESS} - #include <iostream> #include <sstream> -#include "android-base/macros.h" - #include "Idmap2Service.h" +#include "android-base/macros.h" using android::BinderService; using android::IPCThreadState; diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 5cc0664b2bed..ebbb5ffc989d 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -52,11 +52,9 @@ #include <vector> #include "android-base/macros.h" - #include "androidfw/ApkAssets.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" - #include "idmap2/Policies.h" namespace android::idmap2 { diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h index cd76b84ccc0a..90c698cc6e49 100644 --- a/cmds/idmap2/include/idmap2/Policies.h +++ b/cmds/idmap2/include/idmap2/Policies.h @@ -17,11 +17,10 @@ #include <string> #include <vector> +#include "Result.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" -#include "Result.h" - #ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ #define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h index c388f4b94251..5111bb2eaab2 100644 --- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h @@ -21,7 +21,6 @@ #include <memory> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" namespace android { diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h index 7e33b3b06fc3..2e543d4fabdd 100644 --- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h +++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h @@ -22,7 +22,6 @@ #include <string> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" namespace android { diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index 1d81c486d504..8797a788dd1d 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -21,7 +21,6 @@ #include <string> #include "androidfw/AssetManager2.h" - #include "idmap2/Idmap.h" #include "idmap2/Result.h" #include "idmap2/ZipFile.h" diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index 96513283ac51..dee2d219cbe1 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ +#include "idmap2/BinaryStreamVisitor.h" + #include <algorithm> #include <cstring> #include <string> #include "android-base/macros.h" -#include "idmap2/BinaryStreamVisitor.h" - namespace android::idmap2 { void BinaryStreamVisitor::Write16(uint16_t value) { diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp index d5fd2ce38b11..5b0ae92df887 100644 --- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp +++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/CommandLineOptions.h" + #include <algorithm> #include <iomanip> #include <iostream> @@ -24,8 +26,6 @@ #include <vector> #include "android-base/macros.h" - -#include "idmap2/CommandLineOptions.h" #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp index a9b68cd6d5d5..3e8e32989a09 100644 --- a/cmds/idmap2/libidmap2/FileUtils.cpp +++ b/cmds/idmap2/libidmap2/FileUtils.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/FileUtils.h" + #include <dirent.h> #include <sys/types.h> #include <unistd.h> @@ -33,8 +35,6 @@ #include "android-base/stringprintf.h" #include "private/android_filesystem_config.h" -#include "idmap2/FileUtils.h" - namespace android::idmap2::utils { std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse, diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 49470b4f4e95..aec1a6fc2bae 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "idmap2/Idmap.h" + #include <algorithm> #include <iostream> #include <iterator> @@ -28,14 +30,12 @@ #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/AssetManager2.h" -#include "utils/String16.h" -#include "utils/String8.h" - -#include "idmap2/Idmap.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/ZipFile.h" +#include "utils/String16.h" +#include "utils/String8.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp index 7c4555633fd2..0a0cecf13932 100644 --- a/cmds/idmap2/libidmap2/Policies.cpp +++ b/cmds/idmap2/libidmap2/Policies.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ +#include "idmap2/Policies.h" + #include <iterator> #include <map> #include <string> #include <vector> #include "androidfw/ResourceTypes.h" - #include "idmap2/Idmap.h" -#include "idmap2/Policies.h" #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp index fc9677994fc0..fbf2c777be9a 100644 --- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/PrettyPrintVisitor.h" + #include <string> #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/ApkAssets.h" - -#include "idmap2/PrettyPrintVisitor.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp index 1149c905a178..dd14fd47aea8 100644 --- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ +#include "idmap2/RawPrintVisitor.h" + #include <cstdarg> #include <string> #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/ApkAssets.h" - -#include "idmap2/RawPrintVisitor.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp index a24836da7f3a..71ba3f0f1ac2 100644 --- a/cmds/idmap2/libidmap2/ResourceUtils.cpp +++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/ResourceUtils.h" + #include <memory> #include <string> #include "androidfw/StringPiece.h" #include "androidfw/Util.h" - -#include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" #include "idmap2/Xml.h" #include "idmap2/ZipFile.h" diff --git a/cmds/idmap2/libidmap2/Result.cpp b/cmds/idmap2/libidmap2/Result.cpp index 471dab2e0411..1eac25f1b955 100644 --- a/cmds/idmap2/libidmap2/Result.cpp +++ b/cmds/idmap2/libidmap2/Result.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ +#include "idmap2/Result.h" + #include <cstdarg> #include "android-base/stringprintf.h" -#include "idmap2/Result.h" - namespace android::idmap2 { // NOLINTNEXTLINE(cert-dcl50-cpp) diff --git a/cmds/idmap2/libidmap2/Xml.cpp b/cmds/idmap2/libidmap2/Xml.cpp index 0075a922d676..264586829c47 100644 --- a/cmds/idmap2/libidmap2/Xml.cpp +++ b/cmds/idmap2/libidmap2/Xml.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "idmap2/Xml.h" + #include <map> #include <memory> #include <string> #include <utility> -#include "idmap2/Xml.h" - namespace android::idmap2 { std::unique_ptr<const Xml> Xml::Create(const uint8_t* data, size_t size, bool copyData) { diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp index 0f0732466256..812fd6eacbf9 100644 --- a/cmds/idmap2/libidmap2/ZipFile.cpp +++ b/cmds/idmap2/libidmap2/ZipFile.cpp @@ -14,11 +14,12 @@ * limitations under the License. */ +#include "idmap2/ZipFile.h" + #include <memory> #include <string> #include "idmap2/Result.h" -#include "idmap2/ZipFile.h" namespace android::idmap2 { diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp index 9a5b6331cb20..9cdc86ca181a 100644 --- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp +++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp @@ -19,17 +19,14 @@ #include <string> #include <utility> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp index d567af64b16a..6e83fc9abdb1 100644 --- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp +++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp @@ -25,19 +25,16 @@ #include <string> #include <vector> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/file.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" #include "androidfw/LoadedArsc.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - namespace android::idmap2 { TEST(CommandLineOptionsTests, Flag) { diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index 34a0097b0316..f4a306e41e32 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -15,19 +15,17 @@ */ #include <dirent.h> + #include <set> #include <string> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/macros.h" #include "android-base/stringprintf.h" -#include "private/android_filesystem_config.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/FileUtils.h" - -#include "TestHelpers.h" +#include "private/android_filesystem_config.h" using ::testing::NotNull; diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index 91bc4ddb397f..c18744ccb2d5 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -34,16 +34,13 @@ #include <string> #include <vector> +#include "TestHelpers.h" +#include "androidfw/PosixUtils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "androidfw/PosixUtils.h" -#include "private/android_filesystem_config.h" - #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" - -#include "TestHelpers.h" +#include "private/android_filesystem_config.h" using ::android::util::ExecuteBinary; using ::testing::NotNull; @@ -264,6 +261,24 @@ TEST_F(Idmap2BinaryTests, Scan) { ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; ASSERT_EQ(result->stdout, ""); + + // the signature idmap failing to generate should not cause scanning to fail + // clang-format off + result = ExecuteBinary({"idmap2", + "scan", + "--input-directory", GetTestDataPath(), + "--recursive", + "--target-package-name", "test.target", + "--target-apk-path", GetTargetApkPath(), + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); + // clang-format on + ASSERT_THAT(result, NotNull()); + ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; + ASSERT_EQ(result->stdout, expected.str()); + unlink(idmap_static_no_name_path.c_str()); + unlink(idmap_static_2_path.c_str()); + unlink(idmap_static_1_path.c_str()); } TEST_F(Idmap2BinaryTests, Lookup) { diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 621f50337aa3..90fe9a79bd1f 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -15,7 +15,6 @@ */ #include <cstdio> // fclose - #include <fstream> #include <memory> #include <sstream> @@ -23,18 +22,15 @@ #include <utility> #include <vector> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "android-base/macros.h" #include "androidfw/ApkAssets.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" -#include "TestHelpers.h" - using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/Main.cpp b/cmds/idmap2/tests/Main.cpp index 2b13fed8d60d..3e753e974465 100644 --- a/cmds/idmap2/tests/Main.cpp +++ b/cmds/idmap2/tests/Main.cpp @@ -16,12 +16,10 @@ #include <string> +#include "TestHelpers.h" #include "android-base/file.h" - #include "gtest/gtest.h" -#include "TestHelpers.h" - namespace android::idmap2 { std::string GetTestDataPath() { diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp index a76da533cdcb..e30da76ddd98 100644 --- a/cmds/idmap2/tests/PoliciesTests.cpp +++ b/cmds/idmap2/tests/PoliciesTests.cpp @@ -16,9 +16,8 @@ #include <string> -#include "gtest/gtest.h" - #include "TestHelpers.h" +#include "gtest/gtest.h" #include "idmap2/Policies.h" using android::idmap2::PolicyBitmask; diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp index 27a3880f67b6..c41250457678 100644 --- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp @@ -18,18 +18,15 @@ #include <sstream> #include <string> -#include "gmock/gmock.h" -#include "gtest/gtest.h" - +#include "TestHelpers.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" - +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" #include "idmap2/PrettyPrintVisitor.h" -#include "TestHelpers.h" - using ::testing::NotNull; using android::ApkAssets; diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 7372148f0f0e..64518fdf8dee 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -19,14 +19,12 @@ #include <sstream> #include <string> +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - #include "idmap2/Idmap.h" #include "idmap2/RawPrintVisitor.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/ResourceUtilsTests.cpp b/cmds/idmap2/tests/ResourceUtilsTests.cpp index ad78685646b4..9ed807ccd8f9 100644 --- a/cmds/idmap2/tests/ResourceUtilsTests.cpp +++ b/cmds/idmap2/tests/ResourceUtilsTests.cpp @@ -17,15 +17,13 @@ #include <memory> #include <string> +#include "TestHelpers.h" +#include "androidfw/ApkAssets.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "androidfw/ApkAssets.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" -#include "TestHelpers.h" - using ::testing::NotNull; namespace android::idmap2 { diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp index 5f4daed521c0..cbced0ae32fb 100644 --- a/cmds/idmap2/tests/ResultTests.cpp +++ b/cmds/idmap2/tests/ResultTests.cpp @@ -20,7 +20,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" - #include "idmap2/Result.h" namespace android::idmap2 { diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index 45525a5b7657..adea3293534d 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -19,6 +19,9 @@ #include <string> +#include "gmock/gmock.h" +#include "gtest/gtest.h" + namespace android::idmap2 { const unsigned char idmap_raw_data[] = { diff --git a/cmds/idmap2/tests/XmlTests.cpp b/cmds/idmap2/tests/XmlTests.cpp index fe79d8f2c5a9..df63211a9209 100644 --- a/cmds/idmap2/tests/XmlTests.cpp +++ b/cmds/idmap2/tests/XmlTests.cpp @@ -16,13 +16,11 @@ #include <cstdio> // fclose -#include "idmap2/Xml.h" -#include "idmap2/ZipFile.h" - +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "TestHelpers.h" +#include "idmap2/Xml.h" +#include "idmap2/ZipFile.h" using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/ZipFileTests.cpp b/cmds/idmap2/tests/ZipFileTests.cpp index 79be43ce0e42..3fca43621945 100644 --- a/cmds/idmap2/tests/ZipFileTests.cpp +++ b/cmds/idmap2/tests/ZipFileTests.cpp @@ -17,13 +17,11 @@ #include <cstdio> // fclose #include <string> -#include "idmap2/Result.h" -#include "idmap2/ZipFile.h" - +#include "TestHelpers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" - -#include "TestHelpers.h" +#include "idmap2/Result.h" +#include "idmap2/ZipFile.h" using ::testing::IsNull; using ::testing::NotNull; diff --git a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml index 9e6a4536cb51..5df0bea555b1 100644 --- a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml +++ b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml @@ -19,5 +19,7 @@ <application android:hasCode="false"/> <overlay android:targetPackage="test.target" - android:targetName="TestResources"/> + android:targetName="TestResources" + android:isStatic="true" + android:priority="10"/> </manifest> diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk Binary files differindex b2c490dcbb90..51e19de082ed 100644 --- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk +++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b6e5754aa65f..0260faae4567 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -16,6 +16,7 @@ package android.app; +import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY; import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; @@ -27,6 +28,8 @@ import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS; import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; import static android.view.Display.INVALID_DISPLAY; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; @@ -193,6 +196,7 @@ import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; final class RemoteServiceException extends AndroidRuntimeException { public RemoteServiceException(String msg) { @@ -224,6 +228,17 @@ public final class ActivityThread extends ClientTransactionHandler { private static final boolean DEBUG_PROVIDER = false; public static final boolean DEBUG_ORDER = false; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; + /** + * If the activity doesn't become idle in time, the timeout will ensure to apply the pending top + * process state. + */ + private static final long PENDING_TOP_PROCESS_STATE_TIMEOUT = 1000; + /** + * The delay to release the provider when it has no more references. It reduces the number of + * transactions for acquiring and releasing provider if the client accesses the provider + * frequently in a short time. + */ + private static final long CONTENT_PROVIDER_RETAIN_TIME = 1000; private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003; /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */ @@ -236,6 +251,11 @@ public final class ActivityThread extends ClientTransactionHandler { // Whether to invoke an activity callback after delivering new configuration. private static final boolean REPORT_TO_ACTIVITY = true; + /** Use foreground GC policy (less pause time) and higher JIT weight. */ + private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0; + /** Use background GC policy and default JIT threshold. */ + private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; + /** * Denotes an invalid sequence number corresponding to a process state change. */ @@ -290,6 +310,11 @@ public final class ActivityThread extends ClientTransactionHandler { // Number of activities that are currently visible on-screen. @UnsupportedAppUsage int mNumVisibleActivities = 0; + private final AtomicInteger mNumLaunchingActivities = new AtomicInteger(); + @GuardedBy("mAppThread") + private int mLastProcessState = PROCESS_STATE_UNKNOWN; + @GuardedBy("mAppThread") + private int mPendingProcessState = PROCESS_STATE_UNKNOWN; ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>(); private int mLastSessionId; @UnsupportedAppUsage @@ -867,17 +892,6 @@ public final class ActivityThread extends ClientTransactionHandler { private class ApplicationThread extends IApplicationThread.Stub { private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; - private int mLastProcessState = -1; - - private void updatePendingConfiguration(Configuration config) { - synchronized (mResourcesManager) { - if (mPendingConfiguration == null || - mPendingConfiguration.isOtherSeqNewer(config)) { - mPendingConfiguration = config; - } - } - } - public final void scheduleSleeping(IBinder token, boolean sleeping) { sendMessage(H.SLEEPING, token, sleeping ? 1 : 0); } @@ -1554,27 +1568,6 @@ public final class ActivityThread extends ClientTransactionHandler { updateProcessState(state, true); } - public void updateProcessState(int processState, boolean fromIpc) { - synchronized (this) { - if (mLastProcessState != processState) { - mLastProcessState = processState; - // Update Dalvik state based on ActivityManager.PROCESS_STATE_* constants. - final int DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE = 0; - final int DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; - int dalvikProcessState = DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE; - // TODO: Tune this since things like gmail sync are important background but not jank perceptible. - if (processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { - dalvikProcessState = DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE; - } - VMRuntime.getRuntime().updateProcessState(dalvikProcessState); - if (false) { - Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState - + (fromIpc ? " (from ipc": "")); - } - } - } - } - /** * Updates {@link #mNetworkBlockSeq}. This is used by ActivityManagerService to inform * the main thread that it needs to wait for the network rules to get updated before @@ -1655,16 +1648,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - @Override - public void updatePendingConfiguration(Configuration config) { - mAppThread.updatePendingConfiguration(config); - } - - @Override - public void updateProcessState(int processState, boolean fromIpc) { - mAppThread.updateProcessState(processState, fromIpc); - } - class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage @@ -1989,6 +1972,7 @@ public final class ActivityThread extends ClientTransactionHandler { if (stopProfiling) { mProfiler.stopProfiling(); } + applyPendingProcessState(); return false; } } @@ -2933,6 +2917,68 @@ public final class ActivityThread extends ClientTransactionHandler { return mActivities.get(token); } + @Override + public void updatePendingConfiguration(Configuration config) { + synchronized (mResourcesManager) { + if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) { + mPendingConfiguration = config; + } + } + } + + @Override + public void updateProcessState(int processState, boolean fromIpc) { + synchronized (mAppThread) { + if (mLastProcessState == processState) { + return; + } + mLastProcessState = processState; + // Defer the top state for VM to avoid aggressive JIT compilation affecting activity + // launch time. + if (processState == ActivityManager.PROCESS_STATE_TOP + && mNumLaunchingActivities.get() > 0) { + mPendingProcessState = processState; + mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT); + } else { + mPendingProcessState = PROCESS_STATE_UNKNOWN; + updateVmProcessState(processState); + } + if (localLOGV) { + Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState + + (fromIpc ? " (from ipc" : "")); + } + } + } + + /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ + private void updateVmProcessState(int processState) { + // TODO: Tune this since things like gmail sync are important background but not jank + // perceptible. + final int state = processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + ? VM_PROCESS_STATE_JANK_PERCEPTIBLE + : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; + VMRuntime.getRuntime().updateProcessState(state); + } + + private void applyPendingProcessState() { + synchronized (mAppThread) { + if (mPendingProcessState == PROCESS_STATE_UNKNOWN) { + return; + } + final int pendingState = mPendingProcessState; + mPendingProcessState = PROCESS_STATE_UNKNOWN; + // Only apply the pending state if the last state doesn't change. + if (pendingState == mLastProcessState) { + updateVmProcessState(pendingState); + } + } + } + + @Override + public void countLaunchingActivities(int num) { + mNumLaunchingActivities.getAndAdd(num); + } + @UnsupportedAppUsage public final void sendActivityResult( IBinder token, String id, int requestCode, @@ -4564,7 +4610,7 @@ public final class ActivityThread extends ClientTransactionHandler { private void onCoreSettingsChange() { if (updateDebugViewAttributeState()) { // request all activities to relaunch for the changes to take place - relaunchAllActivities(); + relaunchAllActivities(false /* preserveWindows */); } } @@ -4581,10 +4627,13 @@ public final class ActivityThread extends ClientTransactionHandler { return previousState != View.sDebugViewAttributes; } - private void relaunchAllActivities() { + private void relaunchAllActivities(boolean preserveWindows) { for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) { - final Activity activity = entry.getValue().activity; - if (!activity.mFinished) { + final ActivityClientRecord r = entry.getValue(); + if (!r.activity.mFinished) { + if (preserveWindows && r.window != null) { + r.mPreserveWindow = true; + } scheduleRelaunchActivity(entry.getKey()); } } @@ -5417,7 +5466,8 @@ public final class ActivityThread extends ClientTransactionHandler { } } - void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { + @VisibleForTesting(visibility = PACKAGE) + public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) { // Updates triggered by package installation go through a package update // receiver. Here we try to capture ApplicationInfo changes that are // caused by other sources, such as overlays. That means we want to be as conservative @@ -5463,7 +5513,8 @@ public final class ActivityThread extends ClientTransactionHandler { newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1; handleConfigurationChanged(newConfig, null); - relaunchAllActivities(); + // Preserve windows to avoid black flickers when overlays change. + relaunchAllActivities(true /* preserveWindows */); } static void freeTextLayoutCachesIfNeeded(int configDiff) { @@ -6498,16 +6549,13 @@ public final class ActivityThread extends ClientTransactionHandler { if (!prc.removePending) { // Schedule the actual remove asynchronously, since we don't know the context // this will be called in. - // TODO: it would be nice to post a delayed message, so - // if we come back and need the same provider quickly - // we will still have it available. if (DEBUG_PROVIDER) { Slog.v(TAG, "releaseProvider: Enqueueing pending removal - " + prc.holder.info.name); } prc.removePending = true; Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc); - mH.sendMessage(msg); + mH.sendMessageDelayed(msg, CONTENT_PROVIDER_RETAIN_TIME); } else { Slog.w(TAG, "Duplicate remove pending of provider " + prc.holder.info.name); } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 9dc8b45a71dc..d308adc52e15 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -78,6 +78,8 @@ public abstract class ClientTransactionHandler { /** Set current process state. */ public abstract void updateProcessState(int processState, boolean fromIpc); + /** Count how many activities are launching. */ + public abstract void countLaunchingActivities(int num); // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions // and deliver callbacks. diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 1785d2a0843b..48ca71690a1b 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -223,7 +223,7 @@ interface IActivityManager { void enterSafeMode(); void noteWakeupAlarm(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String sourcePkg, in String tag); - void removeContentProvider(in IBinder connection, boolean stable); + oneway void removeContentProvider(in IBinder connection, boolean stable); @UnsupportedAppUsage void setRequestedOrientation(in IBinder token, int requestedOrientation); void unbindFinished(in IBinder token, in Intent service, boolean doRebind); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index dd00e5a74382..de64db9def64 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -16,6 +16,8 @@ package android.app; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; @@ -58,23 +60,27 @@ public class TaskInfo { * The base intent of the task (generally the intent that launched the task). This intent can * be used to relaunch the task (if it is no longer running) or brought to the front if it is. */ + @NonNull public Intent baseIntent; /** * The component of the first activity in the task, can be considered the "application" of this * task. */ + @Nullable public ComponentName baseActivity; /** * The component of the top activity in the task, currently showing to the user. */ + @Nullable public ComponentName topActivity; /** * The component of the target activity if this task was started from an activity alias. * Otherwise, this is null. */ + @Nullable public ComponentName origActivity; /** @@ -82,6 +88,7 @@ public class TaskInfo { * alias). * @hide */ + @Nullable public ComponentName realActivity; /** @@ -106,6 +113,7 @@ public class TaskInfo { * The recent activity values for the highest activity in the stack to have set the values. * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}. */ + @Nullable public ActivityManager.TaskDescription taskDescription; /** @@ -126,6 +134,7 @@ public class TaskInfo { * The current configuration of the task. * @hide */ + @NonNull @UnsupportedAppUsage public final Configuration configuration = new Configuration(); diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java index ed45b2f45383..4704661c2b24 100644 --- a/core/java/android/app/prediction/AppTarget.java +++ b/core/java/android/app/prediction/AppTarget.java @@ -204,24 +204,49 @@ public final class AppTarget implements Parcelable { private int mRank; /** - * @param id A unique id for this launchable target. + * @deprecated Use the other Builder constructors. * @hide */ - @SystemApi - @TestApi + @Deprecated public Builder(@NonNull AppTargetId id) { mId = id; } /** - * Sets the target to be an app. - * - * @param packageName PackageName of the app + * @param id A unique id for this launchable target. + * @param packageName PackageName of the target. * @param user The UserHandle of the user which this target belongs to. - * - * @throws IllegalArgumentException is the target is already set + * @hide + */ + @SystemApi + @TestApi + public Builder(@NonNull AppTargetId id, @NonNull String packageName, + @NonNull UserHandle user) { + mId = Preconditions.checkNotNull(id); + mPackageName = Preconditions.checkNotNull(packageName); + mUser = Preconditions.checkNotNull(user); + } + + /** + * @param id A unique id for this launchable target. + * @param info The ShortcutInfo that represents this launchable target. + * @hide + */ + @SystemApi + @TestApi + public Builder(@NonNull AppTargetId id, @NonNull ShortcutInfo info) { + mId = Preconditions.checkNotNull(id); + mShortcutInfo = Preconditions.checkNotNull(info); + mPackageName = info.getPackage(); + mUser = info.getUserHandle(); + } + + /** + * @deprecated Use the appropriate constructor. + * @hide */ @NonNull + @Deprecated public Builder setTarget(@NonNull String packageName, @NonNull UserHandle user) { if (mPackageName != null) { throw new IllegalArgumentException("Target is already set"); @@ -232,11 +257,11 @@ public final class AppTarget implements Parcelable { } /** - * Sets the target to be a ShortcutInfo. - * - * @throws IllegalArgumentException is the target is already set + * @deprecated Use the appropriate constructor. + * @hide */ @NonNull + @Deprecated public Builder setTarget(@NonNull ShortcutInfo info) { setTarget(info.getPackage(), info.getUserHandle()); mShortcutInfo = Preconditions.checkNotNull(info); @@ -244,7 +269,7 @@ public final class AppTarget implements Parcelable { } /** - * Sets the className for the target + * Sets the className for the target. */ @NonNull public Builder setClassName(@NonNull String className) { @@ -253,7 +278,7 @@ public final class AppTarget implements Parcelable { } /** - * Sets the rank of the for the target. + * Sets the rank of the target. */ @NonNull public Builder setRank(@IntRange(from = 0) int rank) { @@ -274,7 +299,7 @@ public final class AppTarget implements Parcelable { @NonNull public AppTarget build() { if (mPackageName == null) { - throw new IllegalStateException("No target set"); + throw new IllegalStateException("No target is set"); } return new AppTarget(mId, mPackageName, mUser, mShortcutInfo, mClassName, mRank); } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index db22f8d1de87..cdf5d4912ad5 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -66,6 +66,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void preExecute(ClientTransactionHandler client, IBinder token) { + client.countLaunchingActivities(1); client.updateProcessState(mProcState, false); client.updatePendingConfiguration(mCurConfig); } @@ -82,6 +83,12 @@ public class LaunchActivityItem extends ClientTransactionItem { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } + @Override + public void postExecute(ClientTransactionHandler client, IBinder token, + PendingTransactionActions pendingActions) { + client.countLaunchingActivities(-1); + } + // ObjectPoolItem implementation diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java index fa3d3b8dea0c..941e9e2ecce5 100644 --- a/core/java/android/attention/AttentionManagerInternal.java +++ b/core/java/android/attention/AttentionManagerInternal.java @@ -46,13 +46,6 @@ public abstract class AttentionManagerInternal { */ public abstract void cancelAttentionCheck(AttentionCallbackInternal callback); - /** - * Disables the dependants. - * - * Example: called if the service does not have sufficient permissions to perform the task. - */ - public abstract void disableSelf(); - /** Internal interface for attention callback. */ public abstract static class AttentionCallbackInternal { /** diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 2174255a3619..30868bfeac66 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -16,6 +16,7 @@ package android.bluetooth.le; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothUuid; @@ -97,7 +98,7 @@ public final class ScanRecord { * Returns a list of service solicitation UUIDs within the advertisement that are used to * identify the Bluetooth GATT services. */ - @Nullable + @NonNull public List<ParcelUuid> getServiceSolicitationUuids() { return mServiceSolicitationUuids; } @@ -297,9 +298,6 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } - if (serviceSolicitationUuids.isEmpty()) { - serviceSolicitationUuids = null; - } return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index a41b5d3fb781..a646e49f4f61 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -17,7 +17,6 @@ package android.content; import android.annotation.UnsupportedAppUsage; -import android.content.ContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Parcel; @@ -59,6 +58,7 @@ public class ContentProviderOperation implements Parcelable { private final ContentValues mValuesBackReferences; private final Map<Integer, Integer> mSelectionArgsBackReferences; private final boolean mYieldAllowed; + private final boolean mFailureAllowed; private final static String TAG = "ContentProviderOperation"; @@ -76,6 +76,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = builder.mSelectionArgsBackReferences; mValuesBackReferences = builder.mValuesBackReferences; mYieldAllowed = builder.mYieldAllowed; + mFailureAllowed = builder.mFailureAllowed; } private ContentProviderOperation(Parcel source) { @@ -98,6 +99,7 @@ public class ContentProviderOperation implements Parcelable { } } mYieldAllowed = source.readInt() != 0; + mFailureAllowed = source.readInt() != 0; } /** @hide */ @@ -111,6 +113,7 @@ public class ContentProviderOperation implements Parcelable { mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences; mValuesBackReferences = cpo.mValuesBackReferences; mYieldAllowed = cpo.mYieldAllowed; + mFailureAllowed = cpo.mFailureAllowed; } public void writeToParcel(Parcel dest, int flags) { @@ -157,6 +160,7 @@ public class ContentProviderOperation implements Parcelable { dest.writeInt(0); } dest.writeInt(mYieldAllowed ? 1 : 0); + dest.writeInt(mFailureAllowed ? 1 : 0); } /** @@ -212,6 +216,11 @@ public class ContentProviderOperation implements Parcelable { return mYieldAllowed; } + /** {@hide} */ + public boolean isFailureAllowed() { + return mFailureAllowed; + } + /** @hide exposed for unit tests */ @UnsupportedAppUsage public int getType() { @@ -274,6 +283,14 @@ public class ContentProviderOperation implements Parcelable { return mType == TYPE_ASSERT; } + private ContentProviderResult fail(String msg) throws OperationApplicationException { + if (mFailureAllowed) { + return new ContentProviderResult(msg); + } else { + throw new OperationApplicationException(msg); + } + } + /** * Applies this operation using the given provider. The backRefs array is used to resolve any * back references that were requested using @@ -297,7 +314,8 @@ public class ContentProviderOperation implements Parcelable { if (mType == TYPE_INSERT) { Uri newUri = provider.insert(mUri, values); if (newUri == null) { - throw new OperationApplicationException("insert failed"); + Log.e(TAG, this.toString()); + return fail("Insert into " + mUri + " returned no result"); } return new ContentProviderResult(newUri); } @@ -329,7 +347,7 @@ public class ContentProviderOperation implements Parcelable { if (!TextUtils.equals(cursorValue, expectedValue)) { // Throw exception when expected values don't match Log.e(TAG, this.toString()); - throw new OperationApplicationException("Found value " + cursorValue + return fail("Found value " + cursorValue + " when expected " + expectedValue + " for column " + projection[i]); } @@ -346,7 +364,7 @@ public class ContentProviderOperation implements Parcelable { if (mExpectedCount != null && mExpectedCount != numRows) { Log.e(TAG, this.toString()); - throw new OperationApplicationException("wrong number of rows: " + numRows); + return fail("Expected " + mExpectedCount + " rows but actual " + numRows); } return new ContentProviderResult(numRows); @@ -491,6 +509,7 @@ public class ContentProviderOperation implements Parcelable { private ContentValues mValuesBackReferences; private Map<Integer, Integer> mSelectionArgsBackReferences; private boolean mYieldAllowed; + private boolean mFailureAllowed; /** Create a {@link Builder} of a given type. The uri must not be null. */ private Builder(int type, Uri uri) { @@ -683,5 +702,11 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = yieldAllowed; return this; } + + /** {@hide} */ + public Builder withFailureAllowed(boolean failureAllowed) { + mFailureAllowed = failureAllowed; + return this; + } } } diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java index d90173ceb3cd..b3010116a115 100644 --- a/core/java/android/content/ContentProviderResult.java +++ b/core/java/android/content/ContentProviderResult.java @@ -16,10 +16,11 @@ package android.content; -import android.content.ContentProvider; import android.net.Uri; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; /** * Contains the result of the application of a {@link ContentProviderOperation}. It is guaranteed @@ -28,26 +29,44 @@ import android.os.Parcel; public class ContentProviderResult implements Parcelable { public final Uri uri; public final Integer count; + /** {@hide} */ + public final String failure; public ContentProviderResult(Uri uri) { - if (uri == null) throw new IllegalArgumentException("uri must not be null"); - this.uri = uri; - this.count = null; + this(Preconditions.checkNotNull(uri), null, null); } public ContentProviderResult(int count) { + this(null, count, null); + } + + /** {@hide} */ + public ContentProviderResult(String failure) { + this(null, null, failure); + } + + /** {@hide} */ + public ContentProviderResult(Uri uri, Integer count, String failure) { + this.uri = uri; this.count = count; - this.uri = null; + this.failure = failure; } public ContentProviderResult(Parcel source) { - int type = source.readInt(); - if (type == 1) { - count = source.readInt(); + if (source.readInt() != 0) { + uri = Uri.CREATOR.createFromParcel(source); + } else { uri = null; + } + if (source.readInt() != 0) { + count = source.readInt(); } else { count = null; - uri = Uri.CREATOR.createFromParcel(source); + } + if (source.readInt() != 0) { + failure = source.readString(); + } else { + failure = null; } } @@ -55,37 +74,63 @@ public class ContentProviderResult implements Parcelable { public ContentProviderResult(ContentProviderResult cpr, int userId) { uri = ContentProvider.maybeAddUserId(cpr.uri, userId); count = cpr.count; + failure = cpr.failure; } + @Override public void writeToParcel(Parcel dest, int flags) { - if (uri == null) { + if (uri != null) { + dest.writeInt(1); + uri.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } + if (count != null) { dest.writeInt(1); dest.writeInt(count); } else { - dest.writeInt(2); - uri.writeToParcel(dest, 0); + dest.writeInt(0); + } + if (failure != null) { + dest.writeInt(1); + dest.writeString(failure); + } else { + dest.writeInt(0); } } + @Override public int describeContents() { return 0; } public static final @android.annotation.NonNull Creator<ContentProviderResult> CREATOR = new Creator<ContentProviderResult>() { + @Override public ContentProviderResult createFromParcel(Parcel source) { return new ContentProviderResult(source); } + @Override public ContentProviderResult[] newArray(int size) { return new ContentProviderResult[size]; } }; + @Override public String toString() { + final StringBuilder sb = new StringBuilder("ContentProviderResult("); + if (uri != null) { + sb.append("uri=" + uri + " "); + } + if (count != null) { + sb.append("count=" + count + " "); + } if (uri != null) { - return "ContentProviderResult(uri=" + uri.toString() + ")"; + sb.append("failure=" + failure + " "); } - return "ContentProviderResult(count=" + count + ")"; + sb.deleteCharAt(sb.length() - 1); + sb.append(")"); + return sb.toString(); } } diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index aff385dc23e1..d05ba799205c 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -428,17 +428,33 @@ public final class HdmiControlManager { } /** - * Get a snapshot of the real-time status of the remote devices. + * Get a snapshot of the real-time status of the devices on the CEC bus. * - * <p>This only applies to devices with multiple HDMI inputs. + * <p>This only applies to devices with switch functionality, which are devices with one + * or more than one HDMI inputs. * - * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices. An empty - * list will be returned if there is none. + * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices on the CEC bus. An + * empty list will be returned if there is none. * * @hide */ + @NonNull + @SystemApi + public List<HdmiDeviceInfo> getConnectedDevices() { + try { + return mService.getDeviceList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #getConnectedDevices()} instead. + */ + @Deprecated @SystemApi - @Nullable public List<HdmiDeviceInfo> getConnectedDevicesList() { try { return mService.getDeviceList(); @@ -448,7 +464,8 @@ public final class HdmiControlManager { } /** - * Power off the target device by sending CEC commands. + * Power off the target device by sending CEC commands. Note that this device can't be the + * current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * @@ -457,6 +474,23 @@ public final class HdmiControlManager { * @hide */ @SystemApi + public void powerOffDevice(@NonNull HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.powerOffRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #powerOffDevice(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void powerOffRemoteDevice(@NonNull HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -468,7 +502,8 @@ public final class HdmiControlManager { } /** - * Power on the target device by sending CEC commands. + * Power on the target device by sending CEC commands. Note that this device can't be the + * current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * @@ -476,6 +511,23 @@ public final class HdmiControlManager { * * @hide */ + public void powerOnDevice(HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.powerOnRemoteDevice( + deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #powerOnDevice(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -487,15 +539,35 @@ public final class HdmiControlManager { } /** - * Request the target device to be the new Active Source by sending CEC commands. + * Request the target device to be the new Active Source by sending CEC commands. Note that + * this device can't be the current device itself. * * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * + * <p>If the target device responds to the command, the users should see the target device + * streaming on their TVs. + * * @param deviceInfo HdmiDeviceInfo of the target device * * @hide */ @SystemApi + public void setActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { + Preconditions.checkNotNull(deviceInfo); + try { + mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #setActiveSource(deviceInfo)} instead. + */ + @Deprecated + @SystemApi public void requestRemoteDeviceToBecomeActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { Preconditions.checkNotNull(deviceInfo); try { @@ -556,7 +628,7 @@ public final class HdmiControlManager { } /** - * Check if the target remote device is connected to the current device. + * Check if the target device is connected to the current device. * * <p>The API also returns true if the current device is the target. * @@ -567,6 +639,27 @@ public final class HdmiControlManager { * @hide */ @SystemApi + public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { + Preconditions.checkNotNull(targetDevice); + mPhysicalAddress = getPhysicalAddress(); + if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + return false; + } + int targetPhysicalAddress = targetDevice.getPhysicalAddress(); + if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { + return false; + } + return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress) + != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE; + } + + /** + * @removed + * @hide + * @deprecated Please use {@link #isDeviceConnected(targetDevice)} instead. + */ + @Deprecated + @SystemApi public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { Preconditions.checkNotNull(targetDevice); mPhysicalAddress = getPhysicalAddress(); diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java index 0604f6a69d00..4b02085726f1 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegate.java @@ -374,4 +374,15 @@ public final class MultiClientInputMethodServiceDelegate { public boolean isUidAllowedOnDisplay(int displayId, int uid) { return mImpl.isUidAllowedOnDisplay(displayId, uid); } + + /** + * Can be called by MSIME to activate/deactivate a client when it is gaining/losing focus + * respectively. + * + * @param clientId client ID to activate/deactivate. + * @param active {@code true} to activate a client. + */ + public void setActive(int clientId, boolean active) { + mImpl.setActive(clientId, active); + } } diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java index bbe3a7fe1b31..04db8d625806 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodServiceDelegateImpl.java @@ -190,4 +190,8 @@ final class MultiClientInputMethodServiceDelegateImpl { boolean isUidAllowedOnDisplay(int displayId, int uid) { return mPrivOps.isUidAllowedOnDisplay(displayId, uid); } + + void setActive(int clientId, boolean active) { + mPrivOps.setActive(clientId, active); + } } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 166de3fde741..6c498c736854 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -493,6 +493,7 @@ public final class DeviceConfig { * @param onPropertyChangedListener The listener to add. * @hide * @see #removeOnPropertyChangedListener(OnPropertyChangedListener) + * @removed */ @SystemApi @TestApi @@ -569,6 +570,7 @@ public final class DeviceConfig { * @param onPropertyChangedListener The listener to remove. * @hide * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener) + * @removed */ @SystemApi @TestApi @@ -737,6 +739,7 @@ public final class DeviceConfig { * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes. * * @hide + * @removed */ @SystemApi @TestApi diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0491c732db81..cc39e56a556b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -955,18 +955,16 @@ public final class Settings { "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"; /** - * Activity Action: Open the advanced power usage details page of an associated app. + * Activity Action: Open the battery details page of an associated app. * <p> * Input: Intent's data URI set with an application name, using the * "package" schema (like "package:com.my.app") * <p> * Output: Nothing. - * - * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL = - "android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL"; + public static final String ACTION_APP_BATTERY_SETTINGS = + "android.settings.APP_BATTERY_SETTINGS"; /** * Activity Action: Show screen for controlling background data @@ -8139,7 +8137,14 @@ public final class Settings { public static final String FACE_UNLOCK_ATTENTION_REQUIRED = "face_unlock_attention_required"; - private static final Validator FACE_UNLOCK_ATTENTION_REQUIRED_VALIDATOR = BOOLEAN_VALIDATOR; + /** + * Whether or not face unlock requires a diverse set of poses during enrollment. This is a + * cached value, the source of truth is obtained through the HAL. + * @hide + */ + public static final String FACE_UNLOCK_DIVERSITY_REQUIRED = + "face_unlock_diversity_required"; + /** * Whether or not face unlock is allowed for apps (through BiometricPrompt). @@ -8797,7 +8802,6 @@ public final class Settings { AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_DISMISSES_KEYGUARD, - FACE_UNLOCK_ATTENTION_REQUIRED, FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, ASSIST_GESTURE_ENABLED, @@ -8964,8 +8968,6 @@ public final class Settings { VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_DISMISSES_KEYGUARD, FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR); - VALIDATORS.put(FACE_UNLOCK_ATTENTION_REQUIRED, - FACE_UNLOCK_ATTENTION_REQUIRED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR); VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR); diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java index 6172ce501590..49ab5db74b87 100644 --- a/core/java/android/service/attention/AttentionService.java +++ b/core/java/android/service/attention/AttentionService.java @@ -21,13 +21,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; -import android.attention.AttentionManagerInternal; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.android.internal.util.Preconditions; -import com.android.server.LocalServices; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -132,19 +130,6 @@ public abstract class AttentionService extends Service { } /** - * Disables the dependants. - * - * Example: called if the service does not have sufficient permissions to perform the task. - */ - public final void disableSelf() { - AttentionManagerInternal attentionManager = LocalServices.getService( - AttentionManagerInternal.class); - if (attentionManager != null) { - attentionManager.disableSelf(); - } - } - - /** * Checks the user attention and calls into the provided callback. * * @param callback the callback to return the result to diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 5be73b92fbc0..d8614a9d66af 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -46,9 +46,9 @@ import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.contentcapture.ContentCaptureSessionId; +import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.IContentCaptureDirectManager; import android.view.contentcapture.MainContentCaptureSession; -import android.view.contentcapture.UserDataRemovalRequest; import com.android.internal.os.IResultReceiver; @@ -138,7 +138,7 @@ public abstract class ContentCaptureService extends Service { } @Override - public void onUserDataRemovalRequest(UserDataRemovalRequest request) { + public void onDataRemovalRequest(DataRemovalRequest request) { mHandler.sendMessage( obtainMessage(ContentCaptureService::handleOnUserDataRemovalRequest, ContentCaptureService.this, request)); @@ -288,12 +288,12 @@ public abstract class ContentCaptureService extends Service { } /** - * Notifies the service that the app requested to remove data associated with the user. + * Notifies the service that the app requested to remove content capture data. * - * @param request the user data requested to be removed + * @param request the content capture data requested to be removed */ - public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - if (sVerbose) Log.v(TAG, "onUserDataRemovalRequest()"); + public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { + if (sVerbose) Log.v(TAG, "onDataRemovalRequest()"); } /** @@ -449,8 +449,8 @@ public abstract class ContentCaptureService extends Service { onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId)); } - private void handleOnUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - onUserDataRemovalRequest(request); + private void handleOnUserDataRemovalRequest(@NonNull DataRemovalRequest request) { + onDataRemovalRequest(request); } private void handleOnActivityEvent(@NonNull ActivityEvent event) { diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl index 03e1b7857837..a7578af94004 100644 --- a/core/java/android/service/contentcapture/IContentCaptureService.aidl +++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl @@ -21,7 +21,7 @@ import android.os.IBinder; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.SnapshotData; import android.view.contentcapture.ContentCaptureContext; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.os.IResultReceiver; @@ -39,6 +39,6 @@ oneway interface IContentCaptureService { in IResultReceiver clientReceiver, int initialState); void onSessionFinished(int sessionId); void onActivitySnapshot(int sessionId, in SnapshotData snapshotData); - void onUserDataRemovalRequest(in UserDataRemovalRequest request); + void onDataRemovalRequest(in DataRemovalRequest request); void onActivityEvent(in ActivityEvent event); } diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index 2288106d8351..d2f22bfac84a 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -418,12 +418,15 @@ public abstract class EuiccService extends Service { * bit map, and original the card Id. The result code may be one of the predefined * {@code RESULT_} constants or any implementation-specific code starting with * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values - * defined in {@code RESOLVABLE_ERROR_}. + * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, + * this method does nothing and returns null by default. * @see android.telephony.euicc.EuiccManager#downloadSubscription */ - public abstract DownloadSubscriptionResult onDownloadSubscription(int slotId, + public DownloadSubscriptionResult onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, - boolean forceDeactivateSim, @Nullable Bundle resolvedBundle); + boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { + return null; + } /** * Download the given subscription. @@ -439,14 +442,14 @@ public abstract class EuiccService extends Service { * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. * @see android.telephony.euicc.EuiccManager#downloadSubscription * - * @deprecated From Q, please use the above - * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. + * @deprecated From Q, a subclass should use and override the above + * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The + * default return value for this one is Integer.MIN_VALUE. */ @Deprecated public @Result int onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim) { - throw new UnsupportedOperationException("onDownloadSubscription(int, " - + "DownloadableSubscription, boolean, boolean) is deprecated."); + return Integer.MIN_VALUE; } /** diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 6f274477431f..5b5f3b843c50 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -123,7 +123,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked - * from an Android automotive system Ui. + * from an Android automotive system UI. */ public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7; diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index f2747cf426fa..1bcfc05224ca 100755 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -34,11 +34,32 @@ public class DisplayMetrics { public static final int DENSITY_LOW = 120; /** + * Intermediate density for screens that sit between {@link #DENSITY_LOW} (120dpi) and + * {@link #DENSITY_MEDIUM} (160dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_MEDIUM} assets for them. + */ + public static final int DENSITY_140 = 140; + + /** * Standard quantized DPI for medium-density screens. */ public static final int DENSITY_MEDIUM = 160; /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_180 = 180; + + /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_200 = 200; + + /** * This is a secondary density, added for some common screen configurations. * It is recommended that applications not generally target this as a first * class density -- that is, don't supply specific graphics for this @@ -58,6 +79,13 @@ public class DisplayMetrics { public static final int DENSITY_TV = 213; /** + * Intermediate density for screens that sit between {@link #DENSITY_MEDIUM} (160dpi) and + * {@link #DENSITY_HIGH} (240dpi). This is not a density that applications should target, + * instead relying on the system to scale their {@link #DENSITY_HIGH} assets for them. + */ + public static final int DENSITY_220 = 220; + + /** * Standard quantized DPI for high-density screens. */ public static final int DENSITY_HIGH = 240; diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 7c69cfde2b9e..1d721516a979 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -551,7 +551,7 @@ public class ScaleGestureDetector { (mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan < mPrevSpan)) || (!mEventBeforeOrAboveStartingGestureEvent && (mCurrSpan > mPrevSpan)); final float spanDiff = (Math.abs(1 - (mCurrSpan / mPrevSpan)) * SCALE_FACTOR); - return mPrevSpan <= 0 ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff); + return mPrevSpan <= mSpanSlop ? 1 : scaleUp ? (1 + spanDiff) : (1 - spanDiff); } return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 51bcbbdb7e7d..c3a94655d7d5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1377,59 +1377,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; - /** @hide */ - @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, - IMPORTANT_FOR_CONTENT_CAPTURE_YES, - IMPORTANT_FOR_CONTENT_CAPTURE_NO, - IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ContentCaptureImportance {} - - /** - * Automatically determine whether a view is important for content capture. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; - - /** - * The view is important for content capture, and its children (if any) will be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; - - /** - * The view is not important for content capture, but its children (if any) will be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; - - /** - * The view is important for content capture, but its children (if any) will not be traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; - - /** - * The view is not important for content capture, and its children (if any) will not be - * traversed. - * - * @see #isImportantForContentCapture() - * @see #setImportantForContentCapture(int) - */ - public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; - - /** * This view is enabled. Interpretation varies by subclass. * Use with ENABLED_MASK when calling setFlags. @@ -3402,55 +3349,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /* End of masks for mPrivateFlags3 */ - /* - * Masks for mPrivateFlags4, as generated by dumpFlags(): - * - * |-------|-------|-------|-------| - * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED - * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED - * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED - * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE - * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK - * |-------|-------|-------|-------| - */ - - /** - * Mask for obtaining the bits which specify how to determine - * whether a view is important for autofill. - * - * <p>NOTE: the important for content capture values were the first flags added and are set in - * the rightmost position, so we don't need to shift them - */ - private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES - | IMPORTANT_FOR_CONTENT_CAPTURE_NO - | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; - - /* - * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods - * should be called. - * - * The idea is to call notifyAppeared() after the view is layout and visible, then call - * notifyDisappeared() when it's gone (without known when it was removed from the parent). - */ - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; - private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; - - /* - * Flags used to cache the value returned by isImportantForContentCapture while the view - * hierarchy is being traversed. - */ - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; - - private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = - PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED - | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - - /* End of masks for mPrivateFlags4 */ - /** @hide */ protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; /** @hide */ @@ -4074,8 +3972,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) int mPrivateFlags3; - private int mPrivateFlags4; - /** * This view's request for the visibility of the status bar. * @hide @@ -5808,11 +5704,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); } break; - case R.styleable.View_importantForContentCapture: - if (a.peekValue(attr) != null) { - setImportantForContentCapture(a.getInt(attr, - IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); - } case R.styleable.View_defaultFocusHighlightEnabled: if (a.peekValue(attr) != null) { setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); @@ -8532,62 +8423,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); } - /** - * Populates a {@link ViewStructure} for content capture. - * - * <p>This method is called after a view is that is eligible for content capture - * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for - * the user, and the activity rendering the view is enabled for content capture) is laid out and - * is visible. - * - * <p>The populated structure is then passed to the service through - * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. - * - * <p><b>Note: </b>views that manage a virtual structure under this view must populate just - * the node representing this view and return right away, then asynchronously report (not - * necessarily in the UI thread) when the children nodes appear, disappear or have their text - * changed by calling - * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, - * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and - * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} - * respectively. The structure for the a child must be created using - * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the - * {@code autofillId} for a child can be obtained either through - * {@code childStructure.getAutofillId()} or - * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. - * - * <p>When the virtual view hierarchy represents a web page, you should also: - * - * <ul> - * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content - * capture events should be generate for that URL. - * <li>Create a new {@link ContentCaptureSession} child for every HTML element that - * renders a new URL (like an {@code IFRAME}) and use that session to notify events from - * that subtree. - * </ul> - * - * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: - * <ul> - * <li>{@link ViewStructure#setChildCount(int)} - * <li>{@link ViewStructure#addChildCount(int)} - * <li>{@link ViewStructure#getChildCount()} - * <li>{@link ViewStructure#newChild(int)} - * <li>{@link ViewStructure#asyncNewChild(int)} - * <li>{@link ViewStructure#asyncCommit()} - * <li>{@link ViewStructure#setWebDomain(String)} - * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} - * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} - * <li>{@link ViewStructure#setDataIsSensitive(boolean)} - * <li>{@link ViewStructure#setAlpha(float)} - * <li>{@link ViewStructure#setElevation(float)} - * <li>{@link ViewStructure#setTransformation(Matrix)} - * - * </ul> - */ - public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { - onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); - } - /** @hide */ protected void onProvideStructure(@NonNull ViewStructure structure, @ViewStructureType int viewFor, int flags) { @@ -9225,265 +9060,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Gets the mode for determining whether this view is important for content capture. - * - * <p>See {@link #setImportantForContentCapture(int)} and - * {@link #isImportantForContentCapture()} for more info about this mode. - * - * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to - * {@link #setImportantForContentCapture(int)}. - * - * @attr ref android.R.styleable#View_importantForContentCapture - */ - @ViewDebug.ExportedProperty(mapping = { - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - to = "yesExcludeDescendants"), - @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, - to = "noExcludeDescendants")}) - @InspectableProperty(enumMapping = { - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, - name = "yesExcludeDescendants"), - @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, - name = "noExcludeDescendants"), - }) - public @ContentCaptureImportance int getImportantForContentCapture() { - // NOTE: the important for content capture values were the first flags added and are set in - // the rightmost position, so we don't need to shift them - return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; - } - - /** - * Sets the mode for determining whether this view is considered important for content capture. - * - * <p>The platform determines the importance for autofill automatically but you - * can use this method to customize the behavior. Typically, a view that provides text should - * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. - * - * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, - * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, - * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, - * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. - * - * @attr ref android.R.styleable#View_importantForContentCapture - */ - public void setImportantForContentCapture(@ContentCaptureImportance int mode) { - // Reset first - mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; - // Then set again - // NOTE: the important for content capture values were the first flags added and are set in - // the rightmost position, so we don't need to shift them - mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); - } - - /** - * Hints the Android System whether this view is considered important for content capture, based - * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics - * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. - * - * <p>See {@link ContentCaptureManager} for more info about content capture. - * - * @return whether the view is considered important for content capture. - * - * @see #setImportantForContentCapture(int) - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - */ - public final boolean isImportantForContentCapture() { - boolean isImportant; - if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { - isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; - return isImportant; - } - - isImportant = calculateIsImportantForContentCapture(); - - mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - if (isImportant) { - mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; - } - mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; - return isImportant; - } - - /** - * Calculates whether the flag is important for content capture so it can be used by - * {@link #isImportantForContentCapture()} while the tree is traversed. - */ - private boolean calculateIsImportantForContentCapture() { - // Check parent mode to ensure we're important - ViewParent parent = mParent; - while (parent instanceof View) { - final int parentImportance = ((View) parent).getImportantForContentCapture(); - if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " - + "content capture because parent " + parent + "'s importance is " - + parentImportance); - } - return false; - } - parent = parent.getParent(); - } - - final int importance = getImportantForContentCapture(); - - // First, check the explicit states. - if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS - || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { - return true; - } - if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS - || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " - + "capture because its importance is " + importance); - } - return false; - } - - // Then use some heuristics to handle AUTO. - if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance - + " on view " + this); - return false; - } - - // View group is important if at least one children also is - if (this instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) this; - for (int i = 0; i < group.getChildCount(); i++) { - final View child = group.getChildAt(i); - if (child.isImportantForContentCapture()) { - return true; - } - } - } - - // If the app developer explicitly set hints or autofill hintsfor it, it's important. - if (getAutofillHints() != null) { - return true; - } - - // Otherwise, assume it's not important... - return false; - } - - /** - * Helper used to notify the {@link ContentCaptureManager} when the view is removed or - * added, based on whether it's laid out and visible, and without knowing if the parent removed - * it from the view hierarchy. - * - * <p>This method is called from many places (visibility changed, view laid out, view attached - * or detached to/from window, etc...) and hence must contain the logic to call the manager, as - * described below: - * - * <ol> - * <li>It should only be called when content capture is enabled for the view. - * <li>It must call viewAppeared() before viewDisappeared() - * <li>viewAppearead() can only be called when the view is visible and laidout - * <li>It should not call the same event twice. - * </ol> - */ - private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { - AttachInfo ai = mAttachInfo; - // Skip it while the view is being laided out for the first time - if (ai != null && !ai.mReadyForContentCaptureUpdates) return; - - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, - "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName()); - } - try { - notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - - private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) { - AttachInfo ai = mAttachInfo; - - // First check if context has client, so it saves a service lookup when it doesn't - if (mContext.getContentCaptureOptions() == null) return; - - // Then check if it's enabled in the context... - final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext) - : mContext.getSystemService(ContentCaptureManager.class); - if (ccm == null || !ccm.isContentCaptureEnabled()) return; - - // ... and finally at the view level - // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() - if (!isImportantForContentCapture()) return; - - ContentCaptureSession session = getContentCaptureSession(); - if (session == null) return; - - if (appeared) { - if (!isLaidOut() || getVisibility() != VISIBLE - || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" - + isLaidOut() + ", visibleToUser=" + isVisibleToUser() - + ", visible=" + (getVisibility() == VISIBLE) - + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) - + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); - } - return; - } - setNotifiedContentCaptureAppeared(); - - if (ai != null) { - ai.delayNotifyContentCaptureEvent(session, this, appeared); - } else { - if (DEBUG_CONTENT_CAPTURE) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); - } - } - } else { - if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 - || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" - + isLaidOut() + ", visibleToUser=" + isVisibleToUser() - + ", visible=" + (getVisibility() == VISIBLE) - + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) - + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 - & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); - } - return; - } - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; - mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; - - if (ai != null) { - ai.delayNotifyContentCaptureEvent(session, this, appeared); - } else { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); - } - } - } - } - - private void setNotifiedContentCaptureAppeared() { - mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; - mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; - } - - /** * Sets the (optional) {@link ContentCaptureSession} associated with this view. * * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to @@ -9739,68 +9315,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Dispatches the initial content capture events for a view structure. - * - * @hide - */ - public void dispatchInitialProvideContentCaptureStructure() { - AttachInfo ai = mAttachInfo; - if (ai == null) { - Log.w(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); - return; - } - ContentCaptureManager ccm = ai.mContentCaptureManager; - if (ccm == null) { - Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " - + "no ContentCaptureManager for " + this); - return; - } - - // We must set it before checkign if the view itself is important, because it might - // initially not be (for example, if it's empty), although that might change later (for - // example, if important views are added) - ai.mReadyForContentCaptureUpdates = true; - - if (!isImportantForContentCapture()) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { - Log.d(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): decorView is not important"); - } - return; - } - - ai.mContentCaptureManager = ccm; - - ContentCaptureSession session = getContentCaptureSession(); - if (session == null) { - if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { - Log.d(CONTENT_CAPTURE_LOG_TAG, - "dispatchProvideContentCaptureStructure(): no session for " + this); - } - return; - } - - session.internalNotifyViewTreeEvent(/* started= */ true); - try { - dispatchProvideContentCaptureStructure(); - } finally { - session.internalNotifyViewTreeEvent(/* started= */ false); - } - } - - /** @hide */ - void dispatchProvideContentCaptureStructure() { - ContentCaptureSession session = getContentCaptureSession(); - if (session != null) { - ViewStructure structure = session.newViewStructure(this); - onProvideContentCaptureStructure(structure, /* flags= */ 0); - setNotifiedContentCaptureAppeared(); - session.notifyViewAppeared(structure); - } - } - - /** * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) * * Note: Called from the default {@link AccessibilityDelegate}. @@ -13753,7 +13267,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void dispatchStartTemporaryDetach() { mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); onStartTemporaryDetach(); } @@ -13780,7 +13293,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyFocusChangeToInputMethodManager(true /* hasFocus */); } notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } /** @@ -14372,8 +13884,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); } /** @@ -18069,7 +17579,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } // Reset content capture caches - mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; mCachedContentCaptureSession = null; if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) @@ -20079,7 +19588,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, needGlobalAttributesUpdate(false); notifyEnterOrExitForAutoFillIfNeeded(true); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @@ -20129,7 +19637,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** @@ -22442,8 +21949,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; notifyEnterOrExitForAutoFillIfNeeded(true); } - - notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); } private boolean hasParentWantsFocus() { @@ -28650,23 +28155,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View mTooltipHost; /** - * The initial structure has been reported so the view is ready to report updates. - */ - boolean mReadyForContentCaptureUpdates; - - /** - * Map(keyed by session) of content capture events that need to be notified after the view - * hierarchy is traversed: value is either the view itself for appearead events, or its - * autofill id for disappeared. - */ - SparseArray<ArrayList<Object>> mContentCaptureEvents; - - /** - * Cached reference to the {@link ContentCaptureManager}. - */ - ContentCaptureManager mContentCaptureManager; - - /** * Creates a new set of attachment information with the specified * events handler and thread. * @@ -28684,31 +28172,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRootCallbacks = effectPlayer; mTreeObserver = new ViewTreeObserver(context); } - - private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, - @NonNull View view, boolean appeared) { - if (mContentCaptureEvents == null) { - // Most of the time there will be just one session, so intial capacity is 1 - mContentCaptureEvents = new SparseArray<>(1); - } - int sessionId = session.getId(); - // TODO: life would be much easier if we provided a MultiMap implementation somwhere... - ArrayList<Object> events = mContentCaptureEvents.get(sessionId); - if (events == null) { - events = new ArrayList<>(); - mContentCaptureEvents.put(sessionId, events); - } - events.add(appeared ? view : view.getAutofillId()); - } - - @Nullable - ContentCaptureManager getContentCaptureManager(@NonNull Context context) { - if (mContentCaptureManager != null) { - return mContentCaptureManager; - } - mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); - return mContentCaptureManager; - } } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 937bd1b34e61..d362024ed525 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3606,7 +3606,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return; } - final ChildListForAutoFillOrContentCapture children = getChildrenForAutofill(flags); + final ChildListForAutofill children = getChildrenForAutofill(flags); final int childrenCount = children.size(); structure.setChildCount(childrenCount); for (int i = 0; i < childrenCount; i++) { @@ -3617,30 +3617,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager children.recycle(); } - /** @hide */ - @Override - public void dispatchProvideContentCaptureStructure() { - super.dispatchProvideContentCaptureStructure(); - - if (!isLaidOut()) return; - - final ChildListForAutoFillOrContentCapture children = getChildrenForContentCapture(); - final int childrenCount = children.size(); - for (int i = 0; i < childrenCount; i++) { - final View child = children.get(i); - child.dispatchProvideContentCaptureStructure(); - } - children.recycle(); - } - /** * Gets the children for autofill. Children for autofill are the first * level descendants that are important for autofill. The returned * child list object is pooled and the caller must recycle it once done. * @hide */ - private @NonNull ChildListForAutoFillOrContentCapture getChildrenForAutofill( + private @NonNull ChildListForAutofill getChildrenForAutofill( @AutofillFlags int flags) { - final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture + final ChildListForAutofill children = ChildListForAutofill .obtain(); populateChildrenForAutofill(children, flags); return children; @@ -3668,34 +3652,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - private @NonNull ChildListForAutoFillOrContentCapture getChildrenForContentCapture() { - final ChildListForAutoFillOrContentCapture children = ChildListForAutoFillOrContentCapture - .obtain(); - populateChildrenForContentCapture(children); - return children; - } - - /** @hide */ - private void populateChildrenForContentCapture(ArrayList<View> list) { - final int childrenCount = mChildrenCount; - if (childrenCount <= 0) { - return; - } - final ArrayList<View> preorderedList = buildOrderedChildList(); - final boolean customOrder = preorderedList == null - && isChildrenDrawingOrderEnabled(); - for (int i = 0; i < childrenCount; i++) { - final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); - final View child = (preorderedList == null) - ? mChildren[childIndex] : preorderedList.get(childIndex); - if (child.isImportantForContentCapture()) { - list.add(child); - } else if (child instanceof ViewGroup) { - ((ViewGroup) child).populateChildrenForContentCapture(list); - } - } - } - private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children, int childIndex) { final View child; @@ -8678,16 +8634,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Pooled class that to hold the children for autifill. */ - private static class ChildListForAutoFillOrContentCapture extends ArrayList<View> { + private static class ChildListForAutofill extends ArrayList<View> { private static final int MAX_POOL_SIZE = 32; - private static final Pools.SimplePool<ChildListForAutoFillOrContentCapture> sPool = + private static final Pools.SimplePool<ChildListForAutofill> sPool = new Pools.SimplePool<>(MAX_POOL_SIZE); - public static ChildListForAutoFillOrContentCapture obtain() { - ChildListForAutoFillOrContentCapture list = sPool.acquire(); + public static ChildListForAutofill obtain() { + ChildListForAutofill list = sPool.acquire(); if (list == null) { - list = new ChildListForAutoFillOrContentCapture(); + list = new ChildListForAutofill(); } return list; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f3b7ad5e557c..5ca70ba9a575 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -105,11 +105,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; -import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; -import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureSession; -import android.view.contentcapture.MainContentCaptureSession; import android.view.inputmethod.InputMethodManager; import android.widget.Scroller; @@ -224,21 +220,6 @@ public final class ViewRootImpl implements ViewParent, */ static final int MAX_TRACKBALL_DELAY = 250; - /** - * Initial value for {@link #mContentCaptureEnabled}. - */ - private static final int CONTENT_CAPTURE_ENABLED_NOT_CHECKED = 0; - - /** - * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code true}. - */ - private static final int CONTENT_CAPTURE_ENABLED_TRUE = 1; - - /** - * Value for {@link #mContentCaptureEnabled} when it was checked and set to {@code false}. - */ - private static final int CONTENT_CAPTURE_ENABLED_FALSE = 2; - @UnsupportedAppUsage static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); @@ -435,10 +416,6 @@ public final class ViewRootImpl implements ViewParent, boolean mLayoutRequested; boolean mFirst; - @Nullable - int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED; - boolean mPerformContentCapture; - boolean mReportNextDraw; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; @@ -637,7 +614,6 @@ public final class ViewRootImpl implements ViewParent, mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; // true for the first time the view is added - mPerformContentCapture = true; // also true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context); @@ -2787,55 +2763,9 @@ public final class ViewRootImpl implements ViewParent, } } - if (mAttachInfo.mContentCaptureEvents != null) { - notifyContentCatpureEvents(); - } - mIsInTraversal = false; } - private void notifyContentCatpureEvents() { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents"); - try { - MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager - .getMainContentCaptureSession(); - for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) { - int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i); - mainSession.notifyViewTreeEvent(sessionId, /* started= */ true); - ArrayList<Object> events = mAttachInfo.mContentCaptureEvents - .valueAt(i); - for_each_event: for (int j = 0; j < events.size(); j++) { - Object event = events.get(j); - if (event instanceof AutofillId) { - mainSession.notifyViewDisappeared(sessionId, (AutofillId) event); - } else if (event instanceof View) { - View view = (View) event; - ContentCaptureSession session = view.getContentCaptureSession(); - if (session == null) { - Log.w(mTag, "no content capture session on view: " + view); - continue for_each_event; - } - int actualId = session.getId(); - if (actualId != sessionId) { - Log.w(mTag, "content capture session mismatch for view (" + view - + "): was " + sessionId + " before, it's " + actualId + " now"); - continue for_each_event; - } - ViewStructure structure = session.newViewStructure(view); - view.onProvideContentCaptureStructure(structure, /* flags= */ 0); - session.notifyViewAppeared(structure); - } else { - Log.w(mTag, "invalid content capture event: " + event); - } - } - mainSession.notifyViewTreeEvent(sessionId, /* started= */ false); - } - mAttachInfo.mContentCaptureEvents = null; - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - private void notifySurfaceDestroyed() { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks(); @@ -2966,13 +2896,6 @@ public final class ViewRootImpl implements ViewParent, } } mFirstInputStage.onWindowFocusChanged(hasWindowFocus); - - // NOTE: there's no view visibility (appeared / disapparead) events when the windows focus - // is lost, so we don't need to to force a flush - there might be other events such as - // text changes, but these should be flushed independently. - if (hasWindowFocus) { - handleContentCaptureFlush(); - } } private void fireAccessibilityFocusEventIfHasFocusedNode() { @@ -3539,86 +3462,6 @@ public final class ViewRootImpl implements ViewParent, pendingDrawFinished(); } } - if (mPerformContentCapture) { - performContentCaptureInitialReport(); - } - } - - /** - * Checks (and caches) if content capture is enabled for this context. - */ - private boolean isContentCaptureEnabled() { - switch (mContentCaptureEnabled) { - case CONTENT_CAPTURE_ENABLED_TRUE: - return true; - case CONTENT_CAPTURE_ENABLED_FALSE: - return false; - case CONTENT_CAPTURE_ENABLED_NOT_CHECKED: - final boolean reallyEnabled = isContentCaptureReallyEnabled(); - mContentCaptureEnabled = reallyEnabled ? CONTENT_CAPTURE_ENABLED_TRUE - : CONTENT_CAPTURE_ENABLED_FALSE; - return reallyEnabled; - default: - Log.w(TAG, "isContentCaptureEnabled(): invalid state " + mContentCaptureEnabled); - return false; - } - - } - - /** - * Checks (without caching) if content capture is enabled for this context. - */ - private boolean isContentCaptureReallyEnabled() { - // First check if context supports it, so it saves a service lookup when it doesn't - if (mContext.getContentCaptureOptions() == null) return false; - - final ContentCaptureManager ccm = mAttachInfo.getContentCaptureManager(mContext); - // Then check if it's enabled in the contex itself. - if (ccm == null || !ccm.isContentCaptureEnabled()) return false; - - return true; - } - - private void performContentCaptureInitialReport() { - mPerformContentCapture = false; // One-time offer! - final View rootView = mView; - if (DEBUG_CONTENT_CAPTURE) { - Log.v(mTag, "performContentCaptureInitialReport() on " + rootView); - } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchContentCapture() for " - + getClass().getSimpleName()); - } - try { - if (!isContentCaptureEnabled()) return; - - // Content capture is a go! - rootView.dispatchInitialProvideContentCaptureStructure(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - - private void handleContentCaptureFlush() { - if (DEBUG_CONTENT_CAPTURE) { - Log.v(mTag, "handleContentCaptureFlush()"); - } - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for " - + getClass().getSimpleName()); - } - try { - if (!isContentCaptureEnabled()) return; - - final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager; - if (ccm == null) { - Log.w(TAG, "No ContentCapture on AttachInfo"); - return; - } - ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } } private boolean draw(boolean fullRedrawNeeded) { diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 253935680cb8..7a6e2adfcaa4 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -191,8 +191,8 @@ import java.util.Set; * * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws * the HTML using {@link Canvas} or native libraries in a different render process), then the view - * is also responsible to notify the session when the virtual elements appear and disappear - see - * {@link View#onProvideContentCaptureStructure(ViewStructure, int)} for more info. + * is also responsible to notify the session when the virtual elements appear and disappear - + * see {@link ContentCaptureSession#newViewStructure(View)} for more info. */ @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE) public final class ContentCaptureManager { @@ -578,16 +578,15 @@ public final class ContentCaptureManager { } /** - * Called by the app to request the content capture service to remove user-data associated with - * some context. + * Called by the app to remove content capture data associated with some context. * - * @param request object specifying what user data should be removed. + * @param request object specifying what data should be removed. */ - public void removeUserData(@NonNull UserDataRemovalRequest request) { + public void removeData(@NonNull DataRemovalRequest request) { Preconditions.checkNotNull(request); try { - mService.removeUserData(request); + mService.removeData(request); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 7761038f8af1..17a1fb405321 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -356,10 +356,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Notifies the Content Capture Service that a node has been added to the view structure. * - * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or - * automatically by the Android System for views that return {@code true} on - * {@link View#onProvideContentCaptureStructure(ViewStructure, int)}. - * * @param node node that has been added. */ public final void notifyViewAppeared(@NonNull ViewStructure node) { @@ -378,9 +374,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Notifies the Content Capture Service that a node has been removed from the view structure. * - * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or - * automatically by the Android System for standard views. - * * @param id id of the node that has been removed. */ public final void notifyViewDisappeared(@NonNull AutofillId id) { @@ -441,7 +434,46 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Creates a {@link ViewStructure} for a "standard" view. * - * @hide + * <p>This method should be called after a visible view is laid out; the view then must populate + * the structure and pass it to {@link #notifyViewAppeared(ViewStructure)}. + * + * <b>Note: </b>views that manage a virtual structure under this view must populate just the + * node representing this view and return right away, then asynchronously report (not + * necessarily in the UI thread) when the children nodes appear, disappear or have their text + * changed by calling {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, + * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and + * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} respectively. + * The structure for the a child must be created using + * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the + * {@code autofillId} for a child can be obtained either through + * {@code childStructure.getAutofillId()} or + * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. + * + * <p>When the virtual view hierarchy represents a web page, you should also: + * + * <ul> + * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content capture + * events should be generate for that URL. + * <li>Create a new {@link ContentCaptureSession} child for every HTML element that renders a + * new URL (like an {@code IFRAME}) and use that session to notify events from that subtree. + * </ul> + * + * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: + * <ul> + * <li>{@link ViewStructure#setChildCount(int)} + * <li>{@link ViewStructure#addChildCount(int)} + * <li>{@link ViewStructure#getChildCount()} + * <li>{@link ViewStructure#newChild(int)} + * <li>{@link ViewStructure#asyncNewChild(int)} + * <li>{@link ViewStructure#asyncCommit()} + * <li>{@link ViewStructure#setWebDomain(String)} + * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} + * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} + * <li>{@link ViewStructure#setDataIsSensitive(boolean)} + * <li>{@link ViewStructure#setAlpha(float)} + * <li>{@link ViewStructure#setElevation(float)} + * <li>{@link ViewStructure#setTransformation(android.graphics.Matrix)} + * </ul> */ @NonNull public final ViewStructure newViewStructure(@NonNull View view) { diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl b/core/java/android/view/contentcapture/DataRemovalRequest.aidl index fbe47e08ea7c..c89d222d159f 100644 --- a/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl +++ b/core/java/android/view/contentcapture/DataRemovalRequest.aidl @@ -16,4 +16,4 @@ package android.view.contentcapture; -parcelable UserDataRemovalRequest; +parcelable DataRemovalRequest; diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.java b/core/java/android/view/contentcapture/DataRemovalRequest.java index 3e1e4abaa84c..3792846bea71 100644 --- a/core/java/android/view/contentcapture/UserDataRemovalRequest.java +++ b/core/java/android/view/contentcapture/DataRemovalRequest.java @@ -31,14 +31,12 @@ import java.util.ArrayList; import java.util.List; /** - * Class used by apps to request the Content Capture service to remove user-data associated with - * some context. + * Class used by apps to remove content capture data associated with {@link LocusId LocusIds}. */ -public final class UserDataRemovalRequest implements Parcelable { +public final class DataRemovalRequest implements Parcelable { /** - * When set, service should use the {@link LocusId#getId()} as prefix for the data to be - * removed. + * When set, the {@link LocusId#getId()} is the prefix for the data to be removed. */ public static final int FLAG_IS_PREFIX = 0x1; @@ -54,7 +52,7 @@ public final class UserDataRemovalRequest implements Parcelable { private final boolean mForEverything; private ArrayList<LocusIdRequest> mLocusIdRequests; - private UserDataRemovalRequest(@NonNull Builder builder) { + private DataRemovalRequest(@NonNull Builder builder) { mPackageName = ActivityThread.currentActivityThread().getApplication().getPackageName(); mForEverything = builder.mForEverything; if (builder.mLocusIds != null) { @@ -67,7 +65,7 @@ public final class UserDataRemovalRequest implements Parcelable { } } - private UserDataRemovalRequest(@NonNull Parcel parcel) { + private DataRemovalRequest(@NonNull Parcel parcel) { mPackageName = parcel.readString(); mForEverything = parcel.readBoolean(); if (!mForEverything) { @@ -89,7 +87,7 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Checks if app is requesting to remove all user data associated with its package. + * Checks if app is requesting to remove content capture data associated with its package. */ public boolean isForEverything() { return mForEverything; @@ -104,7 +102,7 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Builder for {@link UserDataRemovalRequest} objects. + * Builder for {@link DataRemovalRequest} objects. */ public static final class Builder { @@ -115,7 +113,7 @@ public final class UserDataRemovalRequest implements Parcelable { private boolean mDestroyed; /** - * Requests servive to remove all user data associated with the app's package. + * Requests to remove all content capture data associated with the app's package. * * @return this builder */ @@ -132,7 +130,7 @@ public final class UserDataRemovalRequest implements Parcelable { * Request service to remove data associated with a given {@link LocusId}. * * @param locusId the {@link LocusId} being requested to be removed. - * @param flags either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} + * @param flags either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0} * * @return this builder */ @@ -154,17 +152,17 @@ public final class UserDataRemovalRequest implements Parcelable { } /** - * Builds the {@link UserDataRemovalRequest}. + * Builds the {@link DataRemovalRequest}. */ @NonNull - public UserDataRemovalRequest build() { + public DataRemovalRequest build() { throwIfDestroyed(); Preconditions.checkState(mForEverything || mLocusIds != null, "must call either #forEverything() or add one #addLocusId()"); mDestroyed = true; - return new UserDataRemovalRequest(this); + return new DataRemovalRequest(this); } private void throwIfDestroyed() { @@ -192,19 +190,19 @@ public final class UserDataRemovalRequest implements Parcelable { } } - public static final @android.annotation.NonNull Parcelable.Creator<UserDataRemovalRequest> CREATOR = - new Parcelable.Creator<UserDataRemovalRequest>() { + public static final @android.annotation.NonNull Parcelable.Creator<DataRemovalRequest> CREATOR = + new Parcelable.Creator<DataRemovalRequest>() { @Override @NonNull - public UserDataRemovalRequest createFromParcel(Parcel parcel) { - return new UserDataRemovalRequest(parcel); + public DataRemovalRequest createFromParcel(Parcel parcel) { + return new DataRemovalRequest(parcel); } @Override @NonNull - public UserDataRemovalRequest[] newArray(int size) { - return new UserDataRemovalRequest[size]; + public DataRemovalRequest[] newArray(int size) { + return new DataRemovalRequest[size]; } }; @@ -231,7 +229,7 @@ public final class UserDataRemovalRequest implements Parcelable { /** * Gets the flags associates with request. * - * @return either {@link UserDataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. + * @return either {@link DataRemovalRequest#FLAG_IS_PREFIX} or {@code 0}. */ @NonNull public @Flags int getFlags() { diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl index 7335073c59e0..ced941744387 100644 --- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl +++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl @@ -19,7 +19,7 @@ package android.view.contentcapture; import android.content.ComponentName; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureEvent; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import android.os.IBinder; import com.android.internal.os.IResultReceiver; @@ -59,9 +59,9 @@ oneway interface IContentCaptureManager { void getServiceComponentName(in IResultReceiver result); /** - * Requests the removal of user data for the calling user. + * Requests the removal of content capture data for the calling user. */ - void removeUserData(in UserDataRemovalRequest request); + void removeData(in DataRemovalRequest request); /** * Returns whether the content capture feature is enabled for the calling user. diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index b408129231e7..f2fa67d58839 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -316,16 +316,20 @@ public final class ConversationActions implements Parcelable { private final List<String> mHints; @Nullable private String mCallingPackageName; + @NonNull + private Bundle mExtras; private Request( @NonNull List<Message> conversation, @NonNull TextClassifier.EntityConfig typeConfig, int maxSuggestions, - @Nullable @Hint List<String> hints) { + @Nullable @Hint List<String> hints, + @NonNull Bundle extras) { mConversation = Preconditions.checkNotNull(conversation); mTypeConfig = Preconditions.checkNotNull(typeConfig); mMaxSuggestions = maxSuggestions; mHints = hints; + mExtras = extras; } private static Request readFromParcel(Parcel in) { @@ -336,12 +340,13 @@ public final class ConversationActions implements Parcelable { List<String> hints = new ArrayList<>(); in.readStringList(hints); String callingPackageName = in.readString(); - + Bundle extras = in.readBundle(); Request request = new Request( conversation, typeConfig, maxSuggestions, - hints); + hints, + extras); request.setCallingPackageName(callingPackageName); return request; } @@ -353,6 +358,7 @@ public final class ConversationActions implements Parcelable { parcel.writeInt(mMaxSuggestions); parcel.writeStringList(mHints); parcel.writeString(mCallingPackageName); + parcel.writeBundle(mExtras); } @Override @@ -421,6 +427,16 @@ public final class ConversationActions implements Parcelable { return mCallingPackageName; } + /** + * Returns the extended data related to this request. + * + * <p><b>NOTE: </b>Do not modify this bundle. + */ + @NonNull + public Bundle getExtras() { + return mExtras; + } + /** Builder object to construct the {@link Request} object. */ public static final class Builder { @NonNull @@ -431,6 +447,8 @@ public final class ConversationActions implements Parcelable { @Nullable @Hint private List<String> mHints; + @Nullable + private Bundle mExtras; /** * Constructs a builder. @@ -469,6 +487,13 @@ public final class ConversationActions implements Parcelable { return this; } + /** Sets a set of extended data to the request. */ + @NonNull + public Builder setExtras(@Nullable Bundle bundle) { + mExtras = bundle; + return this; + } + /** Builds the {@link Request} object. */ @NonNull public Request build() { @@ -480,7 +505,8 @@ public final class ConversationActions implements Parcelable { mMaxSuggestions, mHints == null ? Collections.emptyList() - : Collections.unmodifiableList(mHints)); + : Collections.unmodifiableList(mHints), + mExtras == null ? Bundle.EMPTY : mExtras); } } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 26dba45666fc..137b67c6e63e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -413,9 +413,6 @@ public class WebView extends AbsoluteLayout if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) { setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES); } - if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); - } if (context == null) { throw new IllegalArgumentException("Invalid context argument"); @@ -2799,11 +2796,6 @@ public class WebView extends AbsoluteLayout } @Override - public void onProvideContentCaptureStructure(ViewStructure structure, int flags) { - mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags); - } - - @Override public void autofill(SparseArray<AutofillValue>values) { mProvider.getViewDelegate().autofill(values); } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index c55f7d654548..c3bb9a0201d0 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -1318,8 +1318,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @ViewStructureType int viewFor, int flags) { super.onProvideStructure(structure, viewFor, flags); - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { final Adapter adapter = getAdapter(); if (adapter == null) return; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index a961783dab7c..618b05f8cb00 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -161,8 +161,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; -import android.view.contentcapture.ContentCaptureManager; -import android.view.contentcapture.ContentCaptureSession; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; @@ -978,9 +976,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) { setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES); } - if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { - setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES); - } setTextInternal(""); @@ -10520,8 +10515,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Notify managers (such as {@link AutofillManager} and {@link ContentCaptureManager}) that are - * interested on text changes. + * Notify managers (such as {@link AutofillManager}) that are interested in text changes. */ private void notifyListeningManagersAfterTextChanged() { @@ -10537,22 +10531,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener afm.notifyValueChanged(TextView.this); } } - - // TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead - // of using isLaidout(), so it's not called in cases where it's laid out but a - // notifyAppeared was not sent. - - // ContentCapture - if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) { - final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class); - if (cm != null && cm.isContentCaptureEnabled()) { - final ContentCaptureSession session = getContentCaptureSession(); - if (session != null) { - // TODO(b/111276913): pass flags when edited by user / add CTS test - session.notifyViewTextChanged(getAutofillId(), getText()); - } - } - } } private boolean isAutofillable() { @@ -11386,8 +11364,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean isPassword = hasPasswordTransformationMethod() || isPasswordInputType(getInputType()); - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { structure.setDataIsSensitive(!mTextSetFromXmlOrResourceId); } @@ -11403,12 +11380,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (!isPassword || viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { if (mLayout == null) { - if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { - Log.w(LOG_TAG, "onProvideContentCaptureStructure(): calling assumeLayout()"); - } assumeLayout(); } Layout layout = mLayout; @@ -11496,8 +11469,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - if (viewFor == VIEW_STRUCTURE_FOR_ASSIST - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { // Extract style information that applies to the TextView as a whole. int style = 0; int typefaceStyle = getTypefaceStyle(); @@ -11525,8 +11497,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener structure.setTextStyle(getTextSize(), getCurrentTextColor(), AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style); } - if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL - || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { + if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { structure.setMinTextEms(getMinEms()); structure.setMaxTextEms(getMaxEms()); int maxLength = -1; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 4d4fe0397791..1597ab735680 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -24,6 +24,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.app.prediction.AppPredictionContext; @@ -131,6 +132,7 @@ import java.util.List; public class ChooserActivity extends ResolverActivity { private static final String TAG = "ChooserActivity"; + /** * Boolean extra to change the following behavior: Normally, ChooserActivity finishes itself * in onStop when launched in a new task. If this extra is set to true, we do not finish @@ -141,7 +143,6 @@ public class ChooserActivity extends ResolverActivity { private static final boolean DEBUG = false; - /** * If {@link #USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true, * {@link AppPredictionManager} will be queried for direct share targets. @@ -433,18 +434,8 @@ public class ChooserActivity extends ResolverActivity { .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType()) .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - final IntentFilter filter = getTargetIntentFilter(); - Bundle extras = new Bundle(); - extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); - AppPredictionManager appPredictionManager = - getSystemService(AppPredictionManager.class); - mAppPredictor = appPredictionManager.createAppPredictionSession( - new AppPredictionContext.Builder(this) - .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) - .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) - .setExtras(extras) - .build()); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor != null) { mAppPredictorCallback = resultList -> { if (isFinishing() || isDestroyed()) { return; @@ -467,8 +458,10 @@ public class ChooserActivity extends ResolverActivity { appTarget.getPackageName(), appTarget.getClassName()))); } sendShareShortcutInfoList(shareShortcutInfos, driList); + sendShortcutManagerShareTargetResultCompleted(); }; - mAppPredictor.registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); + appPredictor + .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); } mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null); @@ -872,7 +865,7 @@ public class ChooserActivity extends ResolverActivity { mChooserHandler.removeMessages(LIST_VIEW_UPDATE_MESSAGE); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT); - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { + if (mAppPredictor != null) { mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback); mAppPredictor.destroy(); } @@ -1205,10 +1198,12 @@ public class ChooserActivity extends ResolverActivity { } private void queryDirectShareTargets(ChooserListAdapter adapter) { - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - mAppPredictor.requestPredictionUpdate(); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor != null) { + appPredictor.requestPredictionUpdate(); return; } + // Default to just querying ShortcutManager if AppPredictor not present. final IntentFilter filter = getTargetIntentFilter(); if (filter == null) { return; @@ -1248,12 +1243,16 @@ public class ChooserActivity extends ResolverActivity { } if (resultMessageSent) { - final Message msg = Message.obtain(); - msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED; - mChooserHandler.sendMessage(msg); + sendShortcutManagerShareTargetResultCompleted(); } } + private void sendShortcutManagerShareTargetResultCompleted() { + final Message msg = Message.obtain(); + msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED; + mChooserHandler.sendMessage(msg); + } + private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); Bundle extras = new Bundle(); @@ -1309,9 +1308,7 @@ public class ChooserActivity extends ResolverActivity { void updateModelAndChooserCounts(TargetInfo info) { if (info != null) { - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { - sendClickToAppPredictor(info); - } + sendClickToAppPredictor(info); final ResolveInfo ri = info.getResolveInfo(); Intent targetIntent = getTargetIntent(); if (ri != null && ri.activityInfo != null && targetIntent != null) { @@ -1332,6 +1329,10 @@ public class ChooserActivity extends ResolverActivity { } private void sendClickToAppPredictor(TargetInfo targetInfo) { + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + if (appPredictor == null) { + return; + } if (!(targetInfo instanceof ChooserTargetInfo)) { return; } @@ -1345,15 +1346,44 @@ public class ChooserActivity extends ResolverActivity { if (shortcutId == null) { return; } - mAppPredictor.notifyAppTargetEvent( + appPredictor.notifyAppTargetEvent( new AppTargetEvent.Builder( - new AppTarget.Builder(new AppTargetId(shortcutId)) - .setTarget(componentName.getPackageName(), getUser()) + // TODO(b/124404997) Send full shortcut info, not just Id with AppTargetId. + new AppTarget.Builder(new AppTargetId(shortcutId), + componentName.getPackageName(), getUser()) .setClassName(componentName.getClassName()) .build(), - AppTargetEvent.ACTION_LAUNCH - ).setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE) - .build()); + AppTargetEvent.ACTION_LAUNCH) + .setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE) + .build()); + } + + @Nullable + private AppPredictor getAppPredictor() { + if (mAppPredictor == null + && getPackageManager().getAppPredictionServicePackageName() != null) { + final IntentFilter filter = getTargetIntentFilter(); + Bundle extras = new Bundle(); + extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); + AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(this) + .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) + .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) + .setExtras(extras) + .build(); + AppPredictionManager appPredictionManager + = getSystemService(AppPredictionManager.class); + mAppPredictor = appPredictionManager.createAppPredictionSession(appPredictionContext); + } + return mAppPredictor; + } + + /** + * This will return an app predictor if it is enabled for direct share sorting + * and if one exists. Otherwise, it returns null. + */ + @Nullable + private AppPredictor getAppPredictorForDirectShareIfEnabled() { + return USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS ? getAppPredictor() : null; } void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) { @@ -2014,7 +2044,8 @@ public class ChooserActivity extends ResolverActivity { } } - if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) { + if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS + || USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { if (DEBUG) { Log.d(TAG, "querying direct share targets from ShortcutManager"); } @@ -2242,7 +2273,7 @@ public class ChooserActivity extends ResolverActivity { return CALLER_TARGET_SCORE_BOOST; } - if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { + if (getAppPredictorForDirectShareIfEnabled() != null) { return SHORTCUT_TARGET_SCORE_BOOST; } diff --git a/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl index 69d9ccc9825b..b5f2147784c0 100644 --- a/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IMultiClientInputMethodPrivilegedOperations.aidl @@ -31,4 +31,5 @@ interface IMultiClientInputMethodPrivilegedOperations { in IMultiClientInputMethodSession multiClientSession, in InputChannel writeChannel); void reportImeWindowTarget(int clientId, int targetWindowHandle, in IBinder imeWindowToken); boolean isUidAllowedOnDisplay(int displayId, int uid); + void setActive(int clientId, boolean active); } diff --git a/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java index 922011707c4a..1cf68872e2cf 100644 --- a/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/MultiClientInputMethodPrivilegedOperations.java @@ -212,4 +212,21 @@ public class MultiClientInputMethodPrivilegedOperations { } } + /** + * Calls {@link IMultiClientInputMethodPrivilegedOperations#setActive(int, boolean)}. + * @param clientId client ID to be set active/inactive + * @param active {@code true} set set active. + */ + @AnyThread + public void setActive(int clientId, boolean active) { + final IMultiClientInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); + if (ops == null) { + return; + } + try { + ops.setActive(clientId, active); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp index 19a1c7212fae..a62dd7c4048f 100644 --- a/core/jni/android_nio_utils.cpp +++ b/core/jni/android_nio_utils.cpp @@ -18,42 +18,51 @@ #include "core_jni_helpers.h" -void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { - assert(array); +namespace { +void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) { + assert(array); jint position; jint limit; jint elementSizeShift; jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); if (pointer != 0L) { + *array = nullptr; + *elements = nullptr; pointer += position << elementSizeShift; return reinterpret_cast<void*>(pointer); } - jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer); *array = jniGetNioBufferBaseArray(_env, buffer); - void * data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); - return reinterpret_cast<void*>(reinterpret_cast<char*>(data) + offset); + *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0); + return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset); } +void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) { + _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT); +} + +} // namespace + +void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) { + void* elements; + return getPointer(_env, buffer, array, &elements); +} -void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, - jboolean commit) { - _env->ReleasePrimitiveArrayCritical(array, data, - commit ? 0 : JNI_ABORT); +void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { + releasePointer(_env, array, data, commit); } /////////////////////////////////////////////////////////////////////////////// -android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, - jboolean commit) { +android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) { fEnv = env; fCommit = commit; - fPointer = android::nio_getPointer(env, nioBuffer, &fArray); + fPointer = getPointer(env, nioBuffer, &fArray, &fElements); } android::AutoBufferPointer::~AutoBufferPointer() { - if (NULL != fArray) { - android::nio_releasePointer(fEnv, fArray, fPointer, fCommit); + if (nullptr != fArray) { + releasePointer(fEnv, fArray, fElements, fCommit); } } diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h index c634cb917719..7c9acd2638da 100644 --- a/core/jni/android_nio_utils.h +++ b/core/jni/android_nio_utils.h @@ -20,7 +20,7 @@ #include <android_runtime/AndroidRuntime.h> namespace android { - + /** * Given an nio.Buffer, return a pointer to it, beginning at its current * position. The returned pointer is only valid for the current JNI stack-frame. @@ -63,9 +63,10 @@ public: private: JNIEnv* fEnv; - void* fPointer; - jarray fArray; - jboolean fCommit; + void* fPointer; // pointer to current buffer position. + void* fElements; // pointer to array element 0 (may be directly in fArray or a copy). + jarray fArray; // pointer to array on managed heap. + jboolean fCommit; // commit data to source if required (when fElements is a copy of fArray). }; } /* namespace android */ diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index 589a6a71d5fd..0db74243222c 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -145,4 +145,8 @@ enum EventId { ESTABLISH_VPN = 118; SET_NETWORK_LOGGING_ENABLED = 119; RETRIEVE_NETWORK_LOGS = 120; + PROVISIONING_PREPARE_TOTAL_TIME_MS = 121; + PROVISIONING_PREPARE_STARTED = 122; + PROVISIONING_PREPARE_COMPLETED = 123; + PROVISIONING_FLOW_TYPE = 124; } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index ed8f2c196b72..ab9a298f3060 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2485,24 +2485,7 @@ <flag name="noExcludeDescendants" value="0x8" /> </attr> - <!-- Hints the Android System whether the view node associated with this View should be - use for content capture purposes. --> - <attr name="importantForContentCapture"> - <!-- Let the Android System use its heuristics to determine if the view is important for content capture. --> - <flag name="auto" value="0" /> - <!-- Hint the Android System that this view is important for content capture, - and its children (if any) will be traversed.. --> - <flag name="yes" value="0x1" /> - <!-- Hint the Android System that this view is *not* important for content capture, - but its children (if any) will be traversed.. --> - <flag name="no" value="0x2" /> - <!-- Hint the Android System that this view is important for content capture, - but its children (if any) will not be traversed. --> - <flag name="yesExcludeDescendants" value="0x4" /> - <!-- Hint the Android System that this view is *not* important for content capture, - and its children (if any) will not be traversed. --> - <flag name="noExcludeDescendants" value="0x8" /> - </attr> + <attr name="__removed6" /> <!-- Boolean that controls whether a view can take focus while in touch mode. If this is true for a view, that view can gain focus when clicked on, and can keep diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index edcc0572cb2e..526818949b3d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -745,10 +745,6 @@ <!-- XXXXXX END OF RESOURCES USING WRONG NAMING CONVENTION --> - <!-- If this is true, notification effects will be played by the notification server. - When false, car notification effects will be handled elsewhere. --> - <bool name="config_enableServerNotificationEffectsForAutomotive">false</bool> - <!-- If this is true, the screen will come on when you unplug usb/power/whatever. --> <bool name="config_unplugTurnsOnScreen">false</bool> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 9a8c754cf197..b7d61c8f8d39 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2922,7 +2922,7 @@ <public name="settingsSliceUri" /> <public name="shell" /> <public name="interactiveUiTimeout" /> - <public name="importantForContentCapture" /> + <public name="__removed6" /> <public name="supportsMultipleDisplays" /> <public name="useAppZygote" /> <public name="__removed1" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f8a2ac9f3e18..4bd2cc758cbb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1521,10 +1521,10 @@ <string name="face_acquired_too_high">Move phone higher.</string> <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] --> <string name="face_acquired_too_low">Move phone lower.</string> - <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_right">Move phone to the right.</string> - <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] --> - <string name="face_acquired_too_left">Move phone to the left.</string> + <!-- Message shown during face acquisition when only the right part of the user's face was detected [CHAR LIMIT=50] --> + <string name="face_acquired_too_right">Move phone to the left.</string> + <!-- Message shown during face acquisition when only the left part of the user's face was detected [CHAR LIMIT=50] --> + <string name="face_acquired_too_left">Move phone to the right.</string> <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] --> <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string> <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index da2f89083fef..94b5da6baa07 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1910,7 +1910,6 @@ <java-symbol type="array" name="config_testLocationProviders" /> <java-symbol type="array" name="config_defaultNotificationVibePattern" /> <java-symbol type="array" name="config_notificationFallbackVibePattern" /> - <java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" /> <java-symbol type="bool" name="config_useAttentionLight" /> <java-symbol type="bool" name="config_adaptive_sleep_available" /> <java-symbol type="bool" name="config_animateScreenLights" /> diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 9cb34895dea4..711eaa7edc2a 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -38,6 +38,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.Display; +import android.view.View; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -153,6 +154,34 @@ public class ActivityThreadTest { } @Test + public void testHandleActivity_assetsChanged() { + final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); + + final IBinder[] token = new IBinder[1]; + final View[] decorView = new View[1]; + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final ActivityThread activityThread = activity.getActivityThread(); + + token[0] = activity.getActivityToken(); + decorView[0] = activity.getWindow().getDecorView(); + + // Relaunches all activities + activityThread.handleApplicationInfoChanged(activity.getApplicationInfo()); + }); + + final View[] newDecorView = new View[1]; + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final ActivityThread activityThread = activity.getActivityThread(); + + final Activity newActivity = activityThread.getActivity(token[0]); + newDecorView[0] = activity.getWindow().getDecorView(); + }); + + assertEquals("Window must be preserved", decorView[0], newDecorView[0]); + } + + @Test public void testHandleActivityConfigurationChanged_DropStaleConfigurations() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java index d2a1dd9a7b5c..4bee24385cc5 100644 --- a/core/tests/coretests/src/android/graphics/BitmapTest.java +++ b/core/tests/coretests/src/android/graphics/BitmapTest.java @@ -22,6 +22,8 @@ import androidx.test.filters.SmallTest; import junit.framework.TestCase; +import java.nio.ByteBuffer; + public class BitmapTest extends TestCase { @SmallTest @@ -262,4 +264,74 @@ public class BitmapTest extends TestCase { assertFalse(hardwareBitmap.isMutable()); assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), hardwareBitmap.getColorSpace()); } + + @SmallTest + public void testCopyWithDirectBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to direct buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final byte padValue = 0x5a; + final int bufferSize = pad + width * height * 2 + pad; + ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize); + + // Write padding + directBuffer.put(0, padValue); + directBuffer.put(directBuffer.limit() - 1, padValue); + + // Copy bitmap + directBuffer.position(pad); + bm1.copyPixelsToBuffer(directBuffer); + assertEquals(directBuffer.position(), pad + width * height * 2); + + // Check padding + assertEquals(directBuffer.get(0), padValue); + assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue); + + // Create bitmap from direct buffer and check match. + directBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(directBuffer); + assertTrue(bm2.sameAs(bm1)); + } + + @SmallTest + public void testCopyWithHeapBuffer() { + // Initialize Bitmap + final int width = 2; + final int height = 2; + Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2); + + // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side + // of bitmap. + final int pad = 1; + final byte padValue = 0x5a; + final int bufferSize = pad + width * height * 2 + pad; + ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize); + + // Write padding + heapBuffer.put(0, padValue); + heapBuffer.put(heapBuffer.limit() - 1, padValue); + + // Copy bitmap + heapBuffer.position(pad); + bm1.copyPixelsToBuffer(heapBuffer); + assertEquals(heapBuffer.position(), pad + width * height * 2); + + // Check padding + assertEquals(heapBuffer.get(0), padValue); + assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue); + + // Create bitmap from heap buffer and check match. + heapBuffer.position(pad); + Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + bm2.copyPixelsFromBuffer(heapBuffer); + assertTrue(bm2.sameAs(bm1)); + } } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index fafd8333f236..0e94abc0dcac 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -709,7 +709,9 @@ public class SettingsBackupTest { Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED, Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS, - Settings.Secure.BIOMETRIC_DEBUG_ENABLED); + Settings.Secure.BIOMETRIC_DEBUG_ENABLED, + Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, + Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index ebbbdec7d376..bdd3038cfee5 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -39,11 +39,13 @@ import android.platform.test.annotations.Presubmit; import android.util.SparseArray; import android.view.SurfaceControl.Transaction; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; +import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -62,7 +64,6 @@ import java.util.List; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsAnimationControlImplTest { @@ -72,15 +73,25 @@ public class InsetsAnimationControlImplTest { private SurfaceControl mTopLeash; private SurfaceControl mNavLeash; private InsetsState mInsetsState; + private static InsetsModeSession sInsetsModeSession; @Mock Transaction mMockTransaction; @Mock InsetsController mMockController; @Mock WindowInsetsAnimationControlListener mMockListener; @Mock SyncRtSurfaceTransactionApplier mMockTransactionApplier; + @BeforeClass + public static void setupOnce() { + sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL); + } + + @AfterClass + public static void tearDownOnce() throws Exception { + sInsetsModeSession.close(); + } + @Before public void setup() { - ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL; MockitoAnnotations.initMocks(this); mTopLeash = new SurfaceControl.Builder(mSession) .setName("testSurface") diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 4d8d3f68f875..1e558287e21b 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -43,7 +43,6 @@ import android.view.WindowManager.LayoutParams; import android.widget.TextView; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -63,7 +62,6 @@ import java.util.concurrent.CountDownLatch; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsControllerTest { diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index a32fa778e736..971e143927b3 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -34,7 +34,6 @@ import android.view.WindowManager.LayoutParams; import android.widget.TextView; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -53,7 +52,6 @@ import org.mockito.MockitoAnnotations; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsSourceConsumerTest { diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java index b55a9c600a61..533a58ef1dfb 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java @@ -24,7 +24,6 @@ import android.graphics.Insets; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; @@ -41,7 +40,6 @@ import org.junit.runner.RunWith; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsSourceTest { diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index 8e167da84e08..a73269a81b11 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -40,7 +40,6 @@ import android.util.SparseIntArray; import android.view.WindowInsets.Type; import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; @@ -56,7 +55,6 @@ import org.junit.runner.RunWith; * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ @Presubmit -@FlakyTest(detail = "Promote once confirmed non-flaky") @RunWith(AndroidJUnit4.class) public class InsetsStateTest { diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index cd885e0b9bcf..7c255c9168cc 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -47,6 +47,6 @@ public class ContentCaptureManagerTest { @Test public void testRemoveUserData_invalid() { - assertThrows(NullPointerException.class, () -> mManager.removeUserData(null)); + assertThrows(NullPointerException.class, () -> mManager.removeData(null)); } } diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 00b4a225c55f..ac039dddb66c 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -42,6 +42,7 @@ import android.content.ClipboardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; @@ -53,7 +54,6 @@ import android.metrics.LogMaker; import android.net.Uri; import android.service.chooser.ChooserTarget; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; @@ -62,10 +62,14 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Function; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -75,21 +79,48 @@ import java.util.List; /** * Chooser activity instrumentation tests */ -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public class ChooserActivityTest { + private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm; + private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM = + pm -> { + PackageManager mock = Mockito.spy(pm); + when(mock.getAppPredictionServicePackageName()).thenReturn(null); + return mock; + }; + + @Parameterized.Parameters + public static Collection packageManagers() { + return Arrays.asList(new Object[][] { + {0, "Default PackageManager", DEFAULT_PM}, + {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM} + }); + } + private static final int CONTENT_PREVIEW_IMAGE = 1; private static final int CONTENT_PREVIEW_FILE = 2; private static final int CONTENT_PREVIEW_TEXT = 3; + private Function<PackageManager, PackageManager> mPackageManagerOverride; + private int mTestNum; @Rule public ActivityTestRule<ChooserWrapperActivity> mActivityRule = new ActivityTestRule<>(ChooserWrapperActivity.class, false, false); + public ChooserActivityTest( + int testNum, + String testName, + Function<PackageManager, PackageManager> packageManagerOverride) { + mPackageManagerOverride = packageManagerOverride; + mTestNum = testNum; + } + @Before public void cleanOverrideData() { sOverrides.reset(); + sOverrides.createPackageManager = mPackageManagerOverride; } @Test diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 9b1f25986d56..99988542d619 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -17,8 +17,8 @@ #include "Properties.h" #include "Debug.h" #include "DeviceInfo.h" -#include "SkTraceEventCommon.h" #include "HWUIProperties.sysprop.h" +#include "SkTraceEventCommon.h" #include <algorithm> #include <cstdlib> @@ -67,7 +67,7 @@ bool Properties::debuggingEnabled = false; bool Properties::isolatedProcess = false; int Properties::contextPriority = 0; -int Properties::defaultRenderAhead = 0; +uint32_t Properties::defaultRenderAhead = 0; static int property_get_int(const char* key, int defaultValue) { char buf[PROPERTY_VALUE_MAX] = { @@ -130,12 +130,9 @@ bool Properties::load() { enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true); - defaultRenderAhead = std::max(0, std::min(2, property_get_int(PROPERTY_RENDERAHEAD, - render_ahead().value_or(0)))); - - if (defaultRenderAhead && sRenderPipelineType == RenderPipelineType::SkiaVulkan) { - ALOGW("hwui.render_ahead of %d ignored because pipeline is skiavk", defaultRenderAhead); - } + defaultRenderAhead = + std::max(0u, std::min(2u, static_cast<uint32_t>(property_get_int( + PROPERTY_RENDERAHEAD, render_ahead().value_or(0))))); return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 3e91c63fcbde..3105e58362ec 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -253,7 +253,7 @@ public: ANDROID_API static int contextPriority; - static int defaultRenderAhead; + static uint32_t defaultRenderAhead; private: static ProfileType sProfileType; diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp index cdad20ec6caa..dc53dd6c27c3 100644 --- a/libs/hwui/TreeInfo.cpp +++ b/libs/hwui/TreeInfo.cpp @@ -25,6 +25,7 @@ TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContex , prepareTextures(mode == MODE_FULL) , canvasContext(canvasContext) , damageGenerationId(canvasContext.getFrameNumber()) - , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {} + , disableForceDark(canvasContext.useForceDark() ? 0 : 1) + , screenSize(canvasContext.getNextFrameSize()) {} } // namespace android::uirenderer diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index 04eabac395f0..7e8d12fd4597 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -20,6 +20,7 @@ #include "utils/Macros.h" #include <utils/Timers.h> +#include "SkSize.h" #include <string> @@ -96,6 +97,8 @@ public: int disableForceDark; + const SkISize screenSize; + struct Out { bool hasFunctors = false; // This is only updated if evaluateAnimations is true diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index da905cf9e63a..5418b337c371 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -547,6 +547,11 @@ void Tree::Cache::clear() { } void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) { + if (canvas->quickReject(bounds)) { + // The RenderNode is on screen, but the AVD is not. + return; + } + // Update the paint for any animatable properties SkPaint paint = inPaint; paint.setAlpha(mProperties.getRootAlpha() * 255); diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index 8508274676fd..66aa8c203799 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -15,6 +15,7 @@ */ #include "ShaderCache.h" +#include <GrContext.h> #include <log/log.h> #include <openssl/sha.h> #include <algorithm> @@ -23,7 +24,6 @@ #include "FileBlobCache.h" #include "Properties.h" #include "utils/TraceUtils.h" -#include <GrContext.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 29d5ef233338..41bcfc25f5c1 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -22,6 +22,7 @@ #include "renderthread/CanvasContext.h" #include <SkImagePriv.h> +#include <SkPathOps.h> namespace android { namespace uirenderer { @@ -35,7 +36,7 @@ void SkiaDisplayList::syncContents(const WebViewSyncData& data) { animatedImage->syncProperties(); } for (auto& vectorDrawable : mVectorDrawables) { - vectorDrawable->syncProperties(); + vectorDrawable.first->syncProperties(); } } @@ -51,6 +52,29 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) } } +static bool intersects(const SkISize screenSize, const Matrix4& mat, const SkRect& bounds) { + Vector3 points[] = { Vector3 {bounds.fLeft, bounds.fTop, 0}, + Vector3 {bounds.fRight, bounds.fTop, 0}, + Vector3 {bounds.fRight, bounds.fBottom, 0}, + Vector3 {bounds.fLeft, bounds.fBottom, 0}}; + float minX, minY, maxX, maxY; + bool first = true; + for (auto& point : points) { + mat.mapPoint3d(point); + if (first) { + minX = maxX = point.x; + minY = maxY = point.y; + first = false; + } else { + minX = std::min(minX, point.x); + minY = std::min(minY, point.y); + maxX = std::max(maxX, point.x); + maxY = std::max(maxY, point.y); + } + } + return SkRect::Make(screenSize).intersects(SkRect::MakeLTRB(minX, minY, maxX, maxY)); +} + bool SkiaDisplayList::prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { @@ -107,15 +131,23 @@ bool SkiaDisplayList::prepareListAndChildren( } } - for (auto& vectorDrawable : mVectorDrawables) { + for (auto& vectorDrawablePair : mVectorDrawables) { // If any vector drawable in the display list needs update, damage the node. + auto& vectorDrawable = vectorDrawablePair.first; if (vectorDrawable->isDirty()) { - isDirty = true; - static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) - ->getVectorDrawables() - ->push_back(vectorDrawable); + Matrix4 totalMatrix; + info.damageAccumulator->computeCurrentTransform(&totalMatrix); + Matrix4 canvasMatrix(vectorDrawablePair.second); + totalMatrix.multiply(canvasMatrix); + const SkRect& bounds = vectorDrawable->properties().getBounds(); + if (intersects(info.screenSize, totalMatrix, bounds)) { + isDirty = true; + static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline()) + ->getVectorDrawables() + ->push_back(vectorDrawable); + vectorDrawable->setPropertyChangeWillBeConsumed(true); + } } - vectorDrawable->setPropertyChangeWillBeConsumed(true); } return isDirty; } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 3219ad1deeff..b79103787023 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -22,6 +22,7 @@ #include "TreeInfo.h" #include "hwui/AnimatedImageDrawable.h" #include "utils/LinearAllocator.h" +#include "utils/Pair.h" #include <deque> @@ -41,12 +42,6 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; namespace skiapipeline { -/** - * This class is intended to be self contained, but still subclasses from - * DisplayList to make it easier to support switching between the two at - * runtime. The downside of this inheritance is that we pay for the overhead - * of the parent class construction/destruction without any real benefit. - */ class SkiaDisplayList { public: size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); } @@ -156,7 +151,17 @@ public: std::deque<RenderNodeDrawable> mChildNodes; std::deque<FunctorDrawable*> mChildFunctors; std::vector<SkImage*> mMutableImages; - std::vector<VectorDrawableRoot*> mVectorDrawables; +private: + std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables; +public: + void appendVD(VectorDrawableRoot* r) { + appendVD(r, SkMatrix::I()); + } + + void appendVD(VectorDrawableRoot* r, const SkMatrix& mat) { + mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat)); + } + std::vector<AnimatedImageDrawable*> mAnimatedImages; DisplayListData mDisplayList; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 570e895a012d..9248eadbd0ef 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -101,7 +101,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con SkiaPipeline::updateLighting(lightGeometry, lightInfo); renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, - SkMatrix::I()); + SkMatrix::I()); layerUpdateQueue->clear(); // Draw visual debugging features @@ -156,8 +156,23 @@ void SkiaOpenGLPipeline::onStop() { } } +static void setBufferCount(ANativeWindow* window, uint32_t extraBuffers) { + int query_value; + int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); + if (err != 0 || query_value < 0) { + ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); + return; + } + auto min_undequeued_buffers = static_cast<uint32_t>(query_value); + + int bufferCount = min_undequeued_buffers + 2 + extraBuffers; + ALOGD("Setting buffer count to %d, min_undequeued %u, extraBuffers %u", + bufferCount, min_undequeued_buffers, extraBuffers); + native_window_set_buffer_count(window, bufferCount); +} + bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, - ColorMode colorMode) { + ColorMode colorMode, uint32_t extraBuffers) { if (mEglSurface != EGL_NO_SURFACE) { mEglManager.destroySurface(mEglSurface); mEglSurface = EGL_NO_SURFACE; @@ -177,6 +192,7 @@ bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); + setBufferCount(surface, extraBuffers); return true; } diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 66929226a5e2..3fe0f92b1924 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -44,7 +44,7 @@ public: FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, - renderthread::ColorMode colorMode) override; + renderthread::ColorMode colorMode, uint32_t extraBuffers) override; void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 721a115c1381..ccc1701dcc0b 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -250,8 +250,9 @@ SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) { } if (mCaptureSequence > 0 || mPictureCapturedCallback) { mRecorder.reset(new SkPictureRecorder()); - SkCanvas* pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(), nullptr, - SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); + SkCanvas* pictureCanvas = + mRecorder->beginRecording(surface->width(), surface->height(), nullptr, + SkPictureRecorder::kPlaybackDrawPicture_RecordFlag); mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height()); mNwayCanvas->addCanvas(surface->getCanvas()); mNwayCanvas->addCanvas(pictureCanvas); @@ -276,8 +277,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) { if (1 == mCaptureSequence) { savePictureAsync(data, mCapturedFile); } else { - savePictureAsync(data, - mCapturedFile + "_" + std::to_string(mCaptureSequence)); + savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence)); } mCaptureSequence--; } @@ -327,7 +327,7 @@ static Rect nodeBounds(RenderNode& node) { auto& props = node.properties(); return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom()); } -} +} // namespace void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, @@ -464,10 +464,20 @@ void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) { // (3) Requires RGBA colors (instead of BGRA). static const uint32_t kOverdrawColors[2][6] = { { - 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, + 0x00000000, + 0x00000000, + 0x2f2f0000, + 0x2f002f00, + 0x3f00003f, + 0x7f00007f, }, { - 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, + 0x00000000, + 0x00000000, + 0x2f2f0000, + 0x4f004f4f, + 0x5f50335f, + 0x7f00007f, }, }; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index d9456355cb88..0a2894945dc8 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -142,8 +142,7 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { FunctorDrawable* functorDrawable; if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - functorDrawable = - mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); } else { functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas()); } @@ -153,7 +152,9 @@ void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { mRecorder.drawVectorDrawable(tree); - mDisplayList->mVectorDrawables.push_back(tree); + SkMatrix mat; + this->getMatrix(&mat); + mDisplayList->appendVD(tree, mat); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index edde6d3e05c0..e8cb219db320 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -18,12 +18,12 @@ #include "DeferredLayerUpdater.h" #include "Readback.h" +#include "ShaderCache.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" #include "VkInteropFunctorDrawable.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" -#include "ShaderCache.h" #include <SkSurface.h> #include <SkTypes.h> @@ -70,8 +70,8 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, con return false; } SkiaPipeline::updateLighting(lightGeometry, lightInfo); - renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - backBuffer, mVkSurface->getCurrentPreTransform()); + renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer, + mVkSurface->getCurrentPreTransform()); ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext()); layerUpdateQueue->clear(); @@ -116,7 +116,7 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { void SkiaVulkanPipeline::onStop() {} bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior, - ColorMode colorMode) { + ColorMode colorMode, uint32_t extraBuffers) { if (mVkSurface) { mVkManager.destroySurface(mVkSurface); mVkSurface = nullptr; @@ -125,8 +125,9 @@ bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBeh setSurfaceColorProperties(colorMode); if (surface) { mRenderThread.requireVkContext(); - mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, - mSurfaceColorType, mRenderThread.getGrContext()); + mVkSurface = + mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace, mSurfaceColorType, + mRenderThread.getGrContext(), extraBuffers); } return mVkSurface != nullptr; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 77a7ab171ee1..31734783de7f 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -43,7 +43,7 @@ public: FrameInfo* currentFrameInfo, bool* requireSwap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior, - renderthread::ColorMode colorMode) override; + renderthread::ColorMode colorMode, uint32_t extraBuffers) override; void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp index 1b9e53b21adb..112792611fc3 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -17,16 +17,16 @@ #include "VkFunctorDrawable.h" #include <private/hwui/DrawVkInfo.h> -#include "renderthread/VulkanManager.h" -#include "renderthread/RenderThread.h" -#include <SkAndroidFrameworkUtils.h> #include <GrBackendDrawableInfo.h> +#include <SkAndroidFrameworkUtils.h> #include <SkImage.h> #include <utils/Color.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> #include <vk/GrVkTypes.h> #include <thread> +#include "renderthread/RenderThread.h" +#include "renderthread/VulkanManager.h" #include "thread/ThreadBase.h" #include "utils/TimeUtils.h" @@ -64,13 +64,13 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { SkMatrix44 mat4(mMatrix); VkFunctorDrawParams params{ - .width = mImageInfo.width(), - .height = mImageInfo.height(), - .color_space_ptr = mImageInfo.colorSpace(), - .clip_left = mClip.fLeft, - .clip_top = mClip.fTop, - .clip_right = mClip.fRight, - .clip_bottom = mClip.fBottom, + .width = mImageInfo.width(), + .height = mImageInfo.height(), + .color_space_ptr = mImageInfo.colorSpace(), + .clip_left = mClip.fLeft, + .clip_top = mClip.fTop, + .clip_right = mClip.fRight, + .clip_bottom = mClip.fBottom, }; mat4.asColMajorf(¶ms.transform[0]); params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer; @@ -87,8 +87,7 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop; } -VkFunctorDrawable::~VkFunctorDrawable() { -} +VkFunctorDrawable::~VkFunctorDrawable() {} void VkFunctorDrawable::onDraw(SkCanvas* canvas) { // "canvas" is either SkNWayCanvas created by SkiaPipeline::tryCapture (SKP capture use case) or @@ -106,9 +105,8 @@ void VkFunctorDrawable::onDraw(SkCanvas* canvas) { SkCanvas* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas); // Enforce "canvas" must be an AlphaFilterCanvas. For GPU canvas, the call should come from // onSnapGpuDrawHandler. - LOG_ALWAYS_FATAL_IF( - gpuCanvas == canvas, - "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!"); + LOG_ALWAYS_FATAL_IF(gpuCanvas == canvas, + "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!"); // This will invoke onSnapGpuDrawHandler and regular draw flow. gpuCanvas->drawDrawable(this); diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 8b02c11911ca..a31081c9a451 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -21,17 +21,16 @@ #include "RenderThread.h" #include "pipeline/skia/ShaderCache.h" #include "pipeline/skia/SkiaMemoryTracer.h" -#include "Properties.h" #include "renderstate/RenderState.h" #include "thread/CommonPool.h" #include <GrContextOptions.h> #include <SkExecutor.h> #include <SkGraphics.h> +#include <SkMathPriv.h> #include <gui/Surface.h> #include <math.h> #include <set> -#include <SkMathPriv.h> namespace android { namespace uirenderer { @@ -79,14 +78,13 @@ void CacheManager::updateContextCacheSizes() { class CommonPoolExecutor : public SkExecutor { public: - virtual void add(std::function<void(void)> func) override { - CommonPool::post(std::move(func)); - } + virtual void add(std::function<void(void)> func) override { CommonPool::post(std::move(func)); } }; static CommonPoolExecutor sDefaultExecutor; -void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) { +void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, + ssize_t size) { contextOptions->fAllowPathMaskCaching = true; // This sets the maximum size for a single texture atlas in the GPU font cache. If necessary, @@ -180,7 +178,8 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) } const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL - ? "GlLayer" : "VkLayer"; + ? "GlLayer" + : "VkLayer"; size_t layerMemoryTotal = 0; for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin(); it != renderState->mActiveLayers.end(); it++) { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4808d68b89ab..2957b143a343 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -17,6 +17,7 @@ #include "CanvasContext.h" #include <GpuMemoryTracker.h> +#include "../Properties.h" #include "AnimationContext.h" #include "EglManager.h" #include "Frame.h" @@ -31,7 +32,6 @@ #include "utils/GLUtils.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" -#include "../Properties.h" #include <cutils/properties.h> #include <private/hwui/DrawGlInfo.h> @@ -41,6 +41,7 @@ #include <sys/stat.h> #include <algorithm> +#include <cstdint> #include <cstdlib> #include <functional> @@ -153,7 +154,8 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { } ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; - bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); + bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, + mRenderAheadDepth); mFrameNumber = -1; @@ -298,7 +300,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy mAnimationContext->startFrame(info.mode); mRenderPipeline->onPrepareTree(); - for (const sp<RenderNode> &node : mRenderNodes) { + for (const sp<RenderNode>& node : mRenderNodes) { // Only the primary target node will be drawn full - all other nodes would get drawn in // real time mode. In case of a window, the primary node is the window content and the other // node(s) are non client / filler nodes. @@ -322,7 +324,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) { nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); - SwapHistory &lastSwap = mSwapHistory.back(); + SwapHistory& lastSwap = mSwapHistory.back(); nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync); // The slight fudge-factor is to deal with cases where // the vsync was estimated due to being slow handling the signal. @@ -405,8 +407,7 @@ void CanvasContext::draw() { SkRect dirty; mDamageAccumulator.finish(&dirty); - if (dirty.isEmpty() && Properties::skipEmptyFrames - && !surfaceRequiresRedraw()) { + if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) { mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); return; } @@ -416,21 +417,21 @@ void CanvasContext::draw() { Frame frame = mRenderPipeline->getFrame(); SkRect windowDirty = computeDirtyRect(frame, &dirty); + if (mRenderAheadDepth) { + auto presentTime = + mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + + (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1)); + native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); + } bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, - mContentDrawBounds, mOpaque, mLightInfo, - mRenderNodes, &(profiler())); + mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, + &(profiler())); int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; waitOnFences(); - if (mRenderAheadDepth) { - auto presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) + - (mRenderThread.timeLord().frameIntervalNanos() * (mRenderAheadDepth + 1)); - native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime); - } - bool requireSwap = false; bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); @@ -510,6 +511,17 @@ void CanvasContext::doFrame() { prepareAndDraw(nullptr); } +SkISize CanvasContext::getNextFrameSize() const { + ReliableSurface* surface = mNativeSurface.get(); + if (surface) { + SkISize size; + surface->query(NATIVE_WINDOW_WIDTH, &size.fWidth); + surface->query(NATIVE_WINDOW_HEIGHT, &size.fHeight); + return size; + } + return {INT32_MAX, INT32_MAX}; +} + void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); @@ -645,21 +657,13 @@ bool CanvasContext::surfaceRequiresRedraw() { } void CanvasContext::applyRenderAheadSettings() { - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - // TODO: Fix SkiaVulkan's assumptions on buffer counts. And SIGBUS crashes. - mRenderAheadDepth = 0; - return; - } - if (mNativeSurface) { - native_window_set_buffer_count(mNativeSurface.get(), 3 + mRenderAheadDepth); - if (!mRenderAheadDepth) { - native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO); - } + if (mNativeSurface && !mRenderAheadDepth) { + native_window_set_buffers_timestamp(mNativeSurface.get(), NATIVE_WINDOW_TIMESTAMP_AUTO); } } -void CanvasContext::setRenderAheadDepth(int renderAhead) { - if (renderAhead < 0 || renderAhead > 2 || renderAhead == mRenderAheadDepth) { +void CanvasContext::setRenderAheadDepth(uint32_t renderAhead) { + if (renderAhead > 2 || renderAhead == mRenderAheadDepth || mNativeSurface) { return; } mRenderAheadDepth = renderAhead; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 4a3119a55c77..912b1257de7b 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -17,30 +17,31 @@ #pragma once #include "DamageAccumulator.h" -#include "Lighting.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" #include "IContextFactory.h" #include "IRenderPipeline.h" #include "LayerUpdateQueue.h" -#include "RenderNode.h" +#include "Lighting.h" #include "ReliableSurface.h" +#include "RenderNode.h" #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" #include <EGL/egl.h> #include <SkBitmap.h> #include <SkRect.h> +#include <SkSize.h> #include <cutils/compiler.h> #include <gui/Surface.h> #include <utils/Functor.h> #include <functional> +#include <future> #include <set> #include <string> #include <vector> -#include <future> namespace android { namespace uirenderer { @@ -112,7 +113,7 @@ public: void setSurface(sp<Surface>&& surface); bool pauseSurface(); void setStopped(bool stopped); - bool hasSurface() { return mNativeSurface.get(); } + bool hasSurface() const { return mNativeSurface.get(); } void allocateBuffers(); void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); @@ -187,9 +188,7 @@ public: mRenderPipeline->setPictureCapturedCallback(callback); } - void setForceDark(bool enable) { - mUseForceDark = enable; - } + void setForceDark(bool enable) { mUseForceDark = enable; } bool useForceDark() { // The force-dark override has the highest priority, followed by the disable setting @@ -204,7 +203,10 @@ public: return mUseForceDark; } - void setRenderAheadDepth(int renderAhead); + // Must be called before setSurface + void setRenderAheadDepth(uint32_t renderAhead); + + SkISize getNextFrameSize() const; private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, @@ -238,7 +240,7 @@ private: // painted onto its surface. bool mIsDirty = false; SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default; - int mRenderAheadDepth = 0; + uint32_t mRenderAheadDepth = 0; struct SwapHistory { SkRect damage; nsecs_t vsyncTime; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 51eeab7e46ce..91dc3bc6e603 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -109,9 +109,8 @@ void DrawFrameTask::run() { // Even if we aren't drawing this vsync pulse the next frame number will still be accurate if (CC_UNLIKELY(callback)) { - context->enqueueFrameWork([callback, frameNr = context->getFrameNumber()]() { - callback(frameNr); - }); + context->enqueueFrameWork( + [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); }); } if (CC_LIKELY(canDrawThisFrame)) { diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 2cc3f362e172..1d553342415c 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -29,10 +29,10 @@ #include <EGL/eglext.h> #include <GLES/gl.h> +#include <gui/Surface.h> +#include <system/window.h> #include <string> #include <vector> -#include <system/window.h> -#include <gui/Surface.h> #define GLES_VERSION 2 @@ -171,8 +171,7 @@ EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavi EGL_NONE}; EGLConfig config = EGL_NO_CONFIG_KHR; EGLint numConfigs = 1; - if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || - numConfigs != 1) { + if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) { return EGL_NO_CONFIG_KHR; } return config; @@ -203,8 +202,7 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi EGL_NONE}; EGLConfig config = EGL_NO_CONFIG_KHR; EGLint numConfigs = 1; - if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || - numConfigs != 1) { + if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) { return EGL_NO_CONFIG_KHR; } return config; @@ -262,7 +260,7 @@ void EglManager::loadConfigs() { mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior); if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) { ALOGE("Device claims wide gamut support, cannot find matching config, error = %s", - eglErrorString()); + eglErrorString()); EglExtensions.pixelFormatFloat = false; } } else if (wideColorType == SkColorType::kN32_SkColorType) { @@ -350,7 +348,7 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, EGLSurface surface = eglCreateWindowSurface( mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs); if (surface == EGL_NO_SURFACE) { - return Error<EGLint> { eglGetError() }; + return Error<EGLint>{eglGetError()}; } if (mSwapBehavior != SwapBehavior::Preserved) { @@ -525,12 +523,8 @@ status_t EglManager::fenceWait(sp<Fence>& fence) { ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno); return -errno; } - EGLint attribs[] = { - EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, - EGL_NONE - }; - EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, - EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { close(fenceFd); ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError()); @@ -559,18 +553,16 @@ status_t EglManager::fenceWait(sp<Fence>& fence) { } status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, - sp<Fence>& nativeFence) { + sp<Fence>& nativeFence) { if (!hasEglContext()) { ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized"); return INVALID_OPERATION; } if (SyncFeatures::getInstance().useNativeFenceSync()) { - EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, - EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); if (sync == EGL_NO_SYNC_KHR) { - ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", - eglGetError()); + ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); @@ -578,7 +570,8 @@ status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, eglDestroySyncKHR(mEglDisplay, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ALOGE("EglManager::createReleaseFence: error dup'ing native fence " - "fd: %#x", eglGetError()); + "fd: %#x", + eglGetError()); return UNKNOWN_ERROR; } nativeFence = new Fence(fenceFd); @@ -592,7 +585,7 @@ status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000); if (result == EGL_FALSE) { ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x", - eglGetError()); + eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence"); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 0502eb88b6a5..3b81014c05e2 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -66,8 +66,8 @@ public: virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; - virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, - ColorMode colorMode) = 0; + virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode, + uint32_t extraBuffers) = 0; virtual void onStop() = 0; virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp index 6f2b9df918e3..ad1fc4921781 100644 --- a/libs/hwui/renderthread/ReliableSurface.cpp +++ b/libs/hwui/renderthread/ReliableSurface.cpp @@ -34,13 +34,13 @@ struct SurfaceExposer : Surface { // Make warnings happy SurfaceExposer() = delete; - using Surface::setBufferCount; - using Surface::setSwapInterval; - using Surface::dequeueBuffer; - using Surface::queueBuffer; using Surface::cancelBuffer; + using Surface::dequeueBuffer; using Surface::lockBuffer_DEPRECATED; using Surface::perform; + using Surface::queueBuffer; + using Surface::setBufferCount; + using Surface::setSwapInterval; }; #define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__) @@ -300,17 +300,9 @@ int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) { int result = callProtected(getWrapped(window), perform, operation, args); va_end(args); - switch (operation) { - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - case NATIVE_WINDOW_SET_USAGE: - case NATIVE_WINDOW_SET_USAGE64: - va_start(args, operation); - getSelf(window)->perform(operation, args); - va_end(args); - break; - default: - break; - } + va_start(args, operation); + getSelf(window)->perform(operation, args); + va_end(args); return result; } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index b58bab1191ed..1a1b9dac37f6 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -84,7 +84,7 @@ void RenderProxy::setName(const char* name) { void RenderProxy::setSurface(const sp<Surface>& surface) { mRenderThread.queue().post( - [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); }); + [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); }); } void RenderProxy::allocateBuffers() { @@ -251,7 +251,7 @@ void RenderProxy::dumpGraphicsMemory(int fd) { void RenderProxy::setProcessStatsBuffer(int fd) { auto& rt = RenderThread::getInstance(); - rt.queue().post([&rt, fd = dup(fd) ]() { + rt.queue().post([&rt, fd = dup(fd)]() { rt.globalProfileData().switchStorageToAshmem(fd); close(fd); }); @@ -285,7 +285,7 @@ void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) void RenderProxy::setPictureCapturedCallback( const std::function<void(sk_sp<SkPicture>&&)>& callback) { mRenderThread.queue().post( - [ this, cb = callback ]() { mContext->setPictureCapturedCallback(cb); }); + [this, cb = callback]() { mContext->setPictureCapturedCallback(cb); }); } void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) { @@ -297,13 +297,13 @@ void RenderProxy::setFrameCompleteCallback(std::function<void(int64_t)>&& callba } void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mRenderThread.queue().post([this, observer = sp{observerPtr}]() { mContext->addFrameMetricsObserver(observer.get()); }); } void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() { + mRenderThread.queue().post([this, observer = sp{observerPtr}]() { mContext->removeFrameMetricsObserver(observer.get()); }); } @@ -313,9 +313,8 @@ void RenderProxy::setForceDark(bool enable) { } void RenderProxy::setRenderAheadDepth(int renderAhead) { - mRenderThread.queue().post([ context = mContext, renderAhead ] { - context->setRenderAheadDepth(renderAhead); - }); + mRenderThread.queue().post( + [context = mContext, renderAhead] { context->setRenderAheadDepth(renderAhead); }); } int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom, @@ -393,9 +392,7 @@ void RenderProxy::releaseVDAtlasEntries() { void RenderProxy::preload() { // Create RenderThread object and start the thread. Then preload Vulkan/EGL driver. auto& thread = RenderThread::getInstance(); - thread.queue().post([&thread]() { - thread.preload(); - }); + thread.queue().post([&thread]() { thread.preload(); }); } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index b76e49ce94a0..eca7d88e4e48 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -16,6 +16,7 @@ #include "RenderThread.h" +#include "../HardwareBitmapUploader.h" #include "CanvasContext.h" #include "DeviceInfo.h" #include "EglManager.h" @@ -29,7 +30,6 @@ #include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" -#include "../HardwareBitmapUploader.h" #ifdef HWUI_GLES_WRAP_ENABLED #include "debug/GlesDriver.h" @@ -410,9 +410,7 @@ bool RenderThread::isCurrent() { void RenderThread::preload() { // EGL driver is always preloaded only if HWUI renders with GL. if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { - std::thread eglInitThread([]() { - eglGetDisplay(EGL_DEFAULT_DISPLAY); - }); + std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); }); eglInitThread.detach(); } else { requireVkContext(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 5f43b488bcf2..6bb26fd6c675 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -22,8 +22,8 @@ #include "../JankTracker.h" #include "CacheManager.h" #include "TimeLord.h" -#include "thread/ThreadBase.h" #include "WebViewFunctorManager.h" +#include "thread/ThreadBase.h" #include "utils/TimeUtils.h" #include <GrContext.h> diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 4011329fa2da..5edf3301b2e8 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -29,7 +29,6 @@ #include <GrBackendSurface.h> #include <GrContext.h> #include <GrTypes.h> -#include <GrTypes.h> #include <vk/GrVkExtensions.h> #include <vk/GrVkTypes.h> @@ -43,7 +42,7 @@ static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& fe // so we can get access to the pNext for the next struct. struct CommonVulkanHeader { VkStructureType sType; - void* pNext; + void* pNext; }; void* pNext = features.pNext; @@ -94,13 +93,13 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe VkResult err; constexpr VkApplicationInfo app_info = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType - nullptr, // pNext - "android framework", // pApplicationName - 0, // applicationVersion - "android framework", // pEngineName - 0, // engineVerison - mAPIVersion, // apiVersion + VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType + nullptr, // pNext + "android framework", // pApplicationName + 0, // applicationVersion + "android framework", // pEngineName + 0, // engineVerison + mAPIVersion, // apiVersion }; { @@ -128,14 +127,14 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe } const VkInstanceCreateInfo instance_create = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType - nullptr, // pNext - 0, // flags - &app_info, // pApplicationInfo - 0, // enabledLayerNameCount - nullptr, // ppEnabledLayerNames - (uint32_t) mInstanceExtensions.size(), // enabledExtensionNameCount - mInstanceExtensions.data(), // ppEnabledExtensionNames + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType + nullptr, // pNext + 0, // flags + &app_info, // pApplicationInfo + 0, // enabledLayerNameCount + nullptr, // ppEnabledLayerNames + (uint32_t)mInstanceExtensions.size(), // enabledExtensionNameCount + mInstanceExtensions.data(), // ppEnabledExtensionNames }; GET_PROC(CreateInstance); @@ -200,11 +199,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe { uint32_t extensionCount = 0; err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount, - nullptr); + nullptr); LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err); mDeviceExtensionsOwner.resize(extensionCount); err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount, - mDeviceExtensionsOwner.data()); + mDeviceExtensionsOwner.data()); LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err); bool hasKHRSwapchainExtension = false; for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) { @@ -216,7 +215,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe LOG_ALWAYS_FATAL_IF(!hasKHRSwapchainExtension); } - auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) { + auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); } @@ -224,7 +223,8 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe }; grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(), - mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data()); + mInstanceExtensions.data(), mDeviceExtensions.size(), + mDeviceExtensions.data()); LOG_ALWAYS_FATAL_IF(!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)); @@ -237,7 +237,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe if (grExtensions.hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) { VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend; - blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) malloc( + blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*)malloc( sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)); LOG_ALWAYS_FATAL_IF(!blend); blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; @@ -247,7 +247,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe } VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature; - ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) malloc( + ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)malloc( sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures)); LOG_ALWAYS_FATAL_IF(!ycbcrFeature); ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; @@ -261,17 +261,17 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe // and we can't depend on it on all platforms features.features.robustBufferAccess = VK_FALSE; - float queuePriorities[1] = { 0.0 }; + float queuePriorities[1] = {0.0}; void* queueNextPtr = nullptr; VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo; - if (Properties::contextPriority != 0 - && grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) { + if (Properties::contextPriority != 0 && + grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) { memset(&queuePriorityCreateInfo, 0, sizeof(VkDeviceQueueGlobalPriorityCreateInfoEXT)); queuePriorityCreateInfo.sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT; queuePriorityCreateInfo.pNext = nullptr; switch (Properties::contextPriority) { case EGL_CONTEXT_PRIORITY_LOW_IMG: @@ -285,41 +285,40 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe break; default: LOG_ALWAYS_FATAL("Unsupported context priority"); - } - queueNextPtr = &queuePriorityCreateInfo; + } + queueNextPtr = &queuePriorityCreateInfo; } const VkDeviceQueueCreateInfo queueInfo[2] = { - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mGraphicsQueueIndex, // queueFamilyIndex - 1, // queueCount - queuePriorities, // pQueuePriorities - }, - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mPresentQueueIndex, // queueFamilyIndex - 1, // queueCount - queuePriorities, // pQueuePriorities - } - }; + { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType + queueNextPtr, // pNext + 0, // VkDeviceQueueCreateFlags + mGraphicsQueueIndex, // queueFamilyIndex + 1, // queueCount + queuePriorities, // pQueuePriorities + }, + { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType + queueNextPtr, // pNext + 0, // VkDeviceQueueCreateFlags + mPresentQueueIndex, // queueFamilyIndex + 1, // queueCount + queuePriorities, // pQueuePriorities + }}; uint32_t queueInfoCount = (mPresentQueueIndex != mGraphicsQueueIndex) ? 2 : 1; const VkDeviceCreateInfo deviceInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType - &features, // pNext - 0, // VkDeviceCreateFlags - queueInfoCount, // queueCreateInfoCount - queueInfo, // pQueueCreateInfos - 0, // layerCount - nullptr, // ppEnabledLayerNames - (uint32_t) mDeviceExtensions.size(), // extensionCount - mDeviceExtensions.data(), // ppEnabledExtensionNames - nullptr, // ppEnabledFeatures + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType + &features, // pNext + 0, // VkDeviceCreateFlags + queueInfoCount, // queueCreateInfoCount + queueInfo, // pQueueCreateInfos + 0, // layerCount + nullptr, // ppEnabledLayerNames + (uint32_t)mDeviceExtensions.size(), // extensionCount + mDeviceExtensions.data(), // ppEnabledExtensionNames + nullptr, // ppEnabledFeatures }; LOG_ALWAYS_FATAL_IF(mCreateDevice(mPhysicalDevice, &deviceInfo, nullptr, &mDevice)); @@ -371,8 +370,8 @@ void VulkanManager::initialize() { // this needs to be on the render queue commandPoolInfo.queueFamilyIndex = mGraphicsQueueIndex; commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - SkDEBUGCODE(VkResult res =) mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, - &mCommandPool); + SkDEBUGCODE(VkResult res =) + mCreateCommandPool(mDevice, &commandPoolInfo, nullptr, &mCommandPool); SkASSERT(VK_SUCCESS == res); } LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE); @@ -391,7 +390,7 @@ void VulkanManager::initialize() { } sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) { - auto getProc = [] (const char* proc_name, VkInstance instance, VkDevice device) { + auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); } @@ -431,7 +430,6 @@ VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const { } Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { - VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer(); if (bufferInfo == nullptr) { @@ -480,7 +478,7 @@ Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) { bufferInfo->skSurface->wait(1, &backendSemaphore); // The following flush blocks the GPU immediately instead of waiting for other // drawing ops. It seems dequeue_fence is not respected otherwise. - //TODO: remove the flush after finding why backendSemaphore is not working. + // TODO: remove the flush after finding why backendSemaphore is not working. bufferInfo->skSurface->flush(); } } @@ -557,15 +555,15 @@ void VulkanManager::destroySurface(VulkanSurface* surface) { VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, - GrContext* grContext) { + SkColorType surfaceColorType, GrContext* grContext, + uint32_t extraBuffers) { LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized"); if (!window) { return nullptr; } return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext, - *this); + *this, extraBuffers); } bool VulkanManager::setupDummyCommandBuffer() { diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index a7a43cc39a45..1a3a0e485523 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -18,16 +18,16 @@ #define VULKANMANAGER_H #if !defined(VK_USE_PLATFORM_ANDROID_KHR) -# define VK_USE_PLATFORM_ANDROID_KHR +#define VK_USE_PLATFORM_ANDROID_KHR #endif #include <vulkan/vulkan.h> #include <GrContextOptions.h> -#include <vk/GrVkExtensions.h> #include <SkSurface.h> #include <ui/Fence.h> #include <utils/StrongPointer.h> #include <vk/GrVkBackendContext.h> +#include <vk/GrVkExtensions.h> #include "Frame.h" #include "IRenderPipeline.h" #include "VulkanSurface.h" @@ -59,8 +59,8 @@ public: // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode, sk_sp<SkColorSpace> surfaceColorSpace, - SkColorType surfaceColorType, - GrContext* grContext); + SkColorType surfaceColorType, GrContext* grContext, + uint32_t extraBuffers); void destroySurface(VulkanSurface* surface); Frame dequeueNextBuffer(VulkanSurface* surface); diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index be78b694f53a..df6b9ed2cdcb 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -16,12 +16,12 @@ #include "VulkanSurface.h" -#include <algorithm> #include <SkSurface.h> +#include <algorithm> #include "VulkanManager.h" -#include "utils/TraceUtils.h" #include "utils/Color.h" +#include "utils/TraceUtils.h" namespace android { namespace uirenderer { @@ -31,10 +31,9 @@ static bool IsTransformSupported(int transform) { // For now, only support pure rotations, not flip or flip-and-rotate, until we have // more time to test them and build sample code. As far as I know we never actually // use anything besides pure rotations anyway. - return transform == 0 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_180 - || transform == NATIVE_WINDOW_TRANSFORM_ROT_270; + return transform == 0 || transform == NATIVE_WINDOW_TRANSFORM_ROT_90 || + transform == NATIVE_WINDOW_TRANSFORM_ROT_180 || + transform == NATIVE_WINDOW_TRANSFORM_ROT_270; } static int InvertTransform(int transform) { @@ -85,16 +84,16 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { } void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize, - const SkISize& maxSize) { + const SkISize& maxSize) { SkISize& windowSize = windowInfo->size; // clamp width & height to handle currentExtent of -1 and protect us from broken hints - if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() - || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) { + if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width() || + windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) { int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width())); int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height())); - ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", - windowSize.width(), windowSize.height(), width, height); + ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]", windowSize.width(), + windowSize.height(), width, height); windowSize.set(width, height); } @@ -145,12 +144,8 @@ class VkSurfaceAutoDeleter { public: VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface, PFN_vkDestroySurfaceKHR destroySurfaceKHR) - : mInstance(instance) - , mSurface(surface) - , mDestroySurfaceKHR(destroySurfaceKHR) {} - ~VkSurfaceAutoDeleter() { - destroy(); - } + : mInstance(instance), mSurface(surface), mDestroySurfaceKHR(destroySurfaceKHR) {} + ~VkSurfaceAutoDeleter() { destroy(); } void destroy() { if (mSurface != VK_NULL_HANDLE) { @@ -166,9 +161,9 @@ private: }; VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, - SkColorType colorType, sk_sp<SkColorSpace> colorSpace, - GrContext* grContext, const VulkanManager& vkManager) { - + SkColorType colorType, sk_sp<SkColorSpace> colorSpace, + GrContext* grContext, const VulkanManager& vkManager, + uint32_t extraBuffers) { VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; @@ -188,10 +183,11 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, vkManager.mDestroySurfaceKHR); SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR( - vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported); - // All physical devices and queue families on Android must be capable of - // presentation with any native window. - SkASSERT(VK_SUCCESS == res && supported);); + vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, + vkSurface, &supported); + // All physical devices and queue families on Android must be capable of + // presentation with any native window. + SkASSERT(VK_SUCCESS == res && supported);); // check for capabilities VkSurfaceCapabilitiesKHR caps; @@ -225,14 +221,13 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, int query_value; int err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { - ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, - query_value); + ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return nullptr; } auto min_undequeued_buffers = static_cast<uint32_t>(query_value); - windowInfo.bufferCount = min_undequeued_buffers - + std::max(VulkanSurface::sTargetBufferCount, caps.minImageCount); + windowInfo.bufferCount = min_undequeued_buffers + + std::max(sTargetBufferCount + extraBuffers, caps.minImageCount); if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) { // Application must settle for fewer images than desired: windowInfo.bufferCount = caps.maxImageCount; @@ -241,8 +236,7 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode, // Currently Skia requires the images to be color attachments and support all transfer // operations. VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags); @@ -336,7 +330,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_data_space(window, windowInfo.dataspace); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) " - "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err); + "failed: %s (%d)", + windowInfo.dataspace, strerror(-err), err); return false; } @@ -344,7 +339,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_dimensions(window, size.width(), size.height()); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) " - "failed: %s (%d)", size.width(), size.height(), strerror(-err), err); + "failed: %s (%d)", + size.width(), size.height(), strerror(-err), err); return false; } @@ -357,7 +353,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform)); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) " - "failed: %s (%d)", windowInfo.transform, strerror(-err), err); + "failed: %s (%d)", + windowInfo.transform, strerror(-err), err); return false; } @@ -366,7 +363,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE); if (err != 0) { ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) " - "failed: %s (%d)", strerror(-err), err); + "failed: %s (%d)", + strerror(-err), err); return false; } @@ -388,12 +386,12 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window } VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, - SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext) + SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext) : mNativeWindow(window) , mWindowInfo(windowInfo) , mGrContext(grContext) , mMinWindowSize(minWindowSize) - , mMaxWindowSize(maxWindowSize) { } + , mMaxWindowSize(maxWindowSize) {} VulkanSurface::~VulkanSurface() { releaseBuffers(); @@ -436,8 +434,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { // value at the end of the function if everything dequeued correctly. mCurrentBufferInfo = nullptr; - - //check if the native window has been resized or rotated and update accordingly + // check if the native window has been resized or rotated and update accordingly SkISize newSize = SkISize::MakeEmpty(); int transformHint = 0; mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth); @@ -457,8 +454,8 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { newWindowInfo.actualSize.height()); if (err != 0) { ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", - newWindowInfo.actualSize.width(), - newWindowInfo.actualSize.height(), strerror(-err), err); + newWindowInfo.actualSize.width(), newWindowInfo.actualSize.height(), + strerror(-err), err); return nullptr; } // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The @@ -469,7 +466,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { if (newWindowInfo.transform != mWindowInfo.transform) { err = native_window_set_buffers_transform(mNativeWindow.get(), - InvertTransform(newWindowInfo.transform)); + InvertTransform(newWindowInfo.transform)); if (err != 0) { ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", newWindowInfo.transform, strerror(-err), err); @@ -512,11 +509,9 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx]; if (bufferInfo->skSurface.get() == nullptr) { - bufferInfo->skSurface = - SkSurface::MakeFromAHardwareBuffer(mGrContext, - ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), - kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), - nullptr); + bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer( + mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()), + kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace), nullptr); if (bufferInfo->skSurface.get() == nullptr) { ALOGE("SkSurface::MakeFromAHardwareBuffer failed"); mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd); @@ -530,19 +525,19 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) { if (!dirtyRect.isEmpty()) { - SkRect transformedRect; - mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect); - SkIRect transformedIRect; - transformedRect.roundOut(&transformedIRect); - transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight); + // native_window_set_surface_damage takes a rectangle in prerotated space + // with a bottom-left origin. That is, top > bottom. + // The dirtyRect is also in prerotated space, so we just need to switch it to + // a bottom-left origin space. - // map to bottom-left coordinate system + SkIRect irect; + dirtyRect.roundOut(&irect); android_native_rect_t aRect; - aRect.left = transformedIRect.x(); - aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height()); - aRect.right = aRect.left + transformedIRect.width(); - aRect.bottom = aRect.top - transformedIRect.height(); + aRect.left = irect.left(); + aRect.top = logicalHeight() - irect.top(); + aRect.right = irect.right(); + aRect.bottom = logicalHeight() - irect.bottom(); int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1); ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err); diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h index 305483fce2d5..b7af596ae762 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -19,8 +19,8 @@ #include <system/window.h> #include <vulkan/vulkan.h> -#include <SkSize.h> #include <SkRefCnt.h> +#include <SkSize.h> #include "IRenderPipeline.h" @@ -34,12 +34,9 @@ class VulkanManager; class VulkanSurface { public: - static VulkanSurface* Create(ANativeWindow* window, - ColorMode colorMode, - SkColorType colorType, - sk_sp<SkColorSpace> colorSpace, - GrContext* grContext, - const VulkanManager& vkManager); + static VulkanSurface* Create(ANativeWindow* window, ColorMode colorMode, SkColorType colorType, + sk_sp<SkColorSpace> colorSpace, GrContext* grContext, + const VulkanManager& vkManager, uint32_t extraBuffers); ~VulkanSurface(); sk_sp<SkSurface> getCurrentSkSurface() { @@ -104,15 +101,10 @@ private: SkMatrix preTransform; }; - VulkanSurface(ANativeWindow* window, - const WindowInfo& windowInfo, - SkISize minWindowSize, - SkISize maxWindowSize, - GrContext* grContext); - static bool UpdateWindow(ANativeWindow* window, - const WindowInfo& windowInfo); - static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, - const SkISize& minSize, + VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, SkISize minWindowSize, + SkISize maxWindowSize, GrContext* grContext); + static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo); + static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize, const SkISize& maxSize); void releaseBuffers(); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 1b4cf7e144bd..6fb164a99ae4 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -23,6 +23,7 @@ #include "pipeline/skia/GLFunctorDrawable.h" #include "pipeline/skia/SkiaDisplayList.h" #include "renderthread/CanvasContext.h" +#include "tests/common/TestContext.h" #include "tests/common/TestUtils.h" using namespace android; @@ -50,13 +51,13 @@ TEST(SkiaDisplayList, reset) { GLFunctorDrawable functorDrawable(nullptr, nullptr, &dummyCanvas); skiaDL->mChildFunctors.push_back(&functorDrawable); skiaDL->mMutableImages.push_back(nullptr); - skiaDL->mVectorDrawables.push_back(nullptr); + skiaDL->appendVD(nullptr); skiaDL->mProjectionReceiver = &drawable; ASSERT_FALSE(skiaDL->mChildNodes.empty()); ASSERT_FALSE(skiaDL->mChildFunctors.empty()); ASSERT_FALSE(skiaDL->mMutableImages.empty()); - ASSERT_FALSE(skiaDL->mVectorDrawables.empty()); + ASSERT_TRUE(skiaDL->hasVectorDrawables()); ASSERT_FALSE(skiaDL->isEmpty()); ASSERT_TRUE(skiaDL->mProjectionReceiver); @@ -65,7 +66,7 @@ TEST(SkiaDisplayList, reset) { ASSERT_TRUE(skiaDL->mChildNodes.empty()); ASSERT_TRUE(skiaDL->mChildFunctors.empty()); ASSERT_TRUE(skiaDL->mMutableImages.empty()); - ASSERT_TRUE(skiaDL->mVectorDrawables.empty()); + ASSERT_FALSE(skiaDL->hasVectorDrawables()); ASSERT_TRUE(skiaDL->isEmpty()); ASSERT_FALSE(skiaDL->mProjectionReceiver); } @@ -110,7 +111,7 @@ TEST(SkiaDisplayList, syncContexts) { SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); - skiaDL.mVectorDrawables.push_back(&vectorDrawable); + skiaDL.appendVD(&vectorDrawable); // ensure that the functor and vectorDrawable are properly synced TestUtils::runOnRenderThread([&](auto&) { @@ -149,9 +150,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { SkiaDisplayList skiaDL; + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + // prepare with a clean VD VectorDrawableRoot cleanVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&cleanVD); + cleanVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&cleanVD); cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit ASSERT_FALSE(cleanVD.isDirty()); @@ -159,11 +165,12 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { TestUtils::MockTreeObserver observer; ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); - ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed()); + ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed()); // prepare again this time adding a dirty VD VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); - skiaDL.mVectorDrawables.push_back(&dirtyVD); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); ASSERT_TRUE(dirtyVD.isDirty()); ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); @@ -191,6 +198,169 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) { canvasContext->destroy(); } +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren_vdOffscreen) { + auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr); + ContextFactory contextFactory; + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory)); + + // Set up a Surface so that we can position the VectorDrawable offscreen. + test::TestContext testContext; + testContext.setRenderOffscreen(true); + auto surface = testContext.surface(); + int width, height; + surface->query(NATIVE_WINDOW_WIDTH, &width); + surface->query(NATIVE_WINDOW_HEIGHT, &height); + canvasContext->setSurface(std::move(surface)); + + TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get()); + DamageAccumulator damageAccumulator; + info.damageAccumulator = &damageAccumulator; + + // The VectorDrawableRoot needs to have bounds on screen (and therefore not + // empty) in order to have PropertyChangeWillBeConsumed set. + const auto bounds = SkRect::MakeIWH(100, 100); + + for (const SkRect b : {bounds.makeOffset(width, 0), + bounds.makeOffset(0, height), + bounds.makeOffset(-bounds.width(), 0), + bounds.makeOffset(0, -bounds.height())}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(b); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // The DamageAccumulator's transform can also result in the + // VectorDrawableRoot being offscreen. + for (const SkISize translate : { SkISize{width, 0}, + SkISize{0, height}, + SkISize{-width, 0}, + SkISize{0, -height}}) { + Matrix4 mat4; + mat4.translate(translate.fWidth, translate.fHeight); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + + // Another way to be offscreen: a matrix from the draw call. + for (const SkMatrix translate : { SkMatrix::MakeTrans(width, 0), + SkMatrix::MakeTrans(0, height), + SkMatrix::MakeTrans(-width, 0), + SkMatrix::MakeTrans(0, -height)}) { + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + + // Verify that the matrices are combined in the right order. + { + // Rotate and then translate, so the VD is offscreen. + Matrix4 mat4; + mat4.loadRotate(180); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix translate = SkMatrix::MakeTrans(50, 50); + skiaDL.appendVD(&dirtyVD, translate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_FALSE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // Switch the order of rotate and translate, so it is on screen. + Matrix4 mat4; + mat4.translate(50, 50); + damageAccumulator.pushTransform(&mat4); + + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix rotate; + rotate.setRotate(180); + skiaDL.appendVD(&dirtyVD, rotate); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + damageAccumulator.popTransform(); + } + { + // An AVD that is larger than the screen. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(SkRect::MakeLTRB(-1, -1, width + 1, height + 1)); + skiaDL.appendVD(&dirtyVD); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } + { + // An AVD whose bounds are not a rectangle after applying a matrix. + SkiaDisplayList skiaDL; + VectorDrawableRoot dirtyVD(new VectorDrawable::Group()); + dirtyVD.mutateProperties()->setBounds(bounds); + SkMatrix mat; + mat.setRotate(45, 50, 50); + skiaDL.appendVD(&dirtyVD, mat); + + ASSERT_TRUE(dirtyVD.isDirty()); + ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed()); + + TestUtils::MockTreeObserver observer; + ASSERT_TRUE(skiaDL.prepareListAndChildren( + observer, info, false, [](RenderNode*, TreeObserver&, TreeInfo&, bool) {})); + ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed()); + } +} + TEST(SkiaDisplayList, updateChildren) { SkiaDisplayList skiaDL; diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index e86cf42fee4d..a671bdada09a 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -31,6 +31,9 @@ #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" +#include <gui/BufferItemConsumer.h> +#include <gui/Surface.h> + using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::renderthread; @@ -421,10 +424,20 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { EXPECT_EQ(1, surface->canvas()->mDrawCounter); } +static sp<Surface> createDummySurface() { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + producer->setMaxDequeuedBufferCount(1); + producer->setAsyncMode(true); + return new Surface(producer); +} + RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { + auto surface = createDummySurface(); auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); EXPECT_FALSE(pipeline->isSurfaceReady()); - EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB)); + EXPECT_TRUE(pipeline->setSurface(surface.get(), SwapBehavior::kSwap_default, ColorMode::SRGB, 0)); EXPECT_TRUE(pipeline->isSurfaceReady()); renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); diff --git a/media/Android.bp b/media/Android.bp index 8746046c220d..5b7b26cef27a 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -64,7 +64,6 @@ filegroup { "apex/java/android/media/IMediaSession2Service.aidl", "apex/java/android/media/MediaConstants.java", "apex/java/android/media/MediaController2.java", - "apex/java/android/media/MediaItem2.java", "apex/java/android/media/MediaSession2.java", "apex/java/android/media/MediaSession2Service.java", "apex/java/android/media/Session2Command.java", diff --git a/media/apex/java/android/media/MediaItem2.java b/media/apex/java/android/media/MediaItem2.java deleted file mode 100644 index ff0d43e41350..000000000000 --- a/media/apex/java/android/media/MediaItem2.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import static android.media.MediaMetadata.METADATA_KEY_MEDIA_ID; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.annotations.GuardedBy; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; - -/** - * A class with information on a single media item with the metadata information. - * <p> - * This API is not generally intended for third party application developers. - * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> - * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a> - * for consistent behavior across all devices. - * <p> - */ -public final class MediaItem2 implements Parcelable { - private static final String TAG = "MediaItem2"; - - // intentionally less than long.MAX_VALUE. - // Declare this first to avoid 'illegal forward reference'. - static final long LONG_MAX = 0x7ffffffffffffffL; - - /** - * Used when a position is unknown. - * - * @see #getEndPosition() - */ - public static final long POSITION_UNKNOWN = LONG_MAX; - - public static final @android.annotation.NonNull Parcelable.Creator<MediaItem2> CREATOR = - new Parcelable.Creator<MediaItem2>() { - @Override - public MediaItem2 createFromParcel(Parcel in) { - return new MediaItem2(in); - } - - @Override - public MediaItem2[] newArray(int size) { - return new MediaItem2[size]; - } - }; - - private static final long UNKNOWN_TIME = -1; - - private final long mStartPositionMs; - private final long mEndPositionMs; - - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private MediaMetadata mMetadata; - @GuardedBy("mLock") - private final List<Pair<OnMetadataChangedListener, Executor>> mListeners = new ArrayList<>(); - - /** - * Used by {@link MediaItem2.Builder}. - */ - // Note: Needs to be protected when we want to allow 3rd party player to define customized - // MediaItem2. - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(Builder builder) { - this(builder.mMetadata, builder.mStartPositionMs, builder.mEndPositionMs); - } - - /** - * Used by Parcelable.Creator. - */ - // Note: Needs to be protected when we want to allow 3rd party player to define customized - // MediaItem2. - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(Parcel in) { - this(in.readParcelable(MediaItem2.class.getClassLoader()), in.readLong(), in.readLong()); - } - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(MediaItem2 item) { - this(item.mMetadata, item.mStartPositionMs, item.mEndPositionMs); - } - - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaItem2(@Nullable MediaMetadata metadata, long startPositionMs, long endPositionMs) { - if (startPositionMs > endPositionMs) { - throw new IllegalArgumentException("Illegal start/end position: " - + startPositionMs + " : " + endPositionMs); - } - if (metadata != null && metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) { - long durationMs = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION); - if (durationMs != UNKNOWN_TIME && endPositionMs != POSITION_UNKNOWN - && endPositionMs > durationMs) { - throw new IllegalArgumentException("endPositionMs shouldn't be greater than" - + " duration in the metdata, endPositionMs=" + endPositionMs - + ", durationMs=" + durationMs); - } - } - mMetadata = metadata; - mStartPositionMs = startPositionMs; - mEndPositionMs = endPositionMs; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(getClass().getSimpleName()); - synchronized (mLock) { - sb.append("{mMetadata=").append(mMetadata); - sb.append(", mStartPositionMs=").append(mStartPositionMs); - sb.append(", mEndPositionMs=").append(mEndPositionMs); - sb.append('}'); - } - return sb.toString(); - } - - /** - * Sets metadata. If the metadata is not {@code null}, its id should be matched with this - * instance's media id. - * - * @param metadata metadata to update - * @see MediaMetadata#METADATA_KEY_MEDIA_ID - */ - public void setMetadata(@Nullable MediaMetadata metadata) { - List<Pair<OnMetadataChangedListener, Executor>> listeners = new ArrayList<>(); - synchronized (mLock) { - if (mMetadata != null && metadata != null - && !TextUtils.equals(getMediaId(), metadata.getString(METADATA_KEY_MEDIA_ID))) { - Log.d(TAG, "MediaItem2's media ID shouldn't be changed"); - return; - } - mMetadata = metadata; - listeners.addAll(mListeners); - } - - for (Pair<OnMetadataChangedListener, Executor> pair : listeners) { - final OnMetadataChangedListener listener = pair.first; - pair.second.execute(new Runnable() { - @Override - public void run() { - listener.onMetadataChanged(MediaItem2.this); - } - }); - } - } - - /** - * Gets the metadata of the media. - * - * @return metadata from the session - */ - public @Nullable MediaMetadata getMetadata() { - synchronized (mLock) { - return mMetadata; - } - } - - /** - * Return the position in milliseconds at which the playback will start. - * @return the position in milliseconds at which the playback will start - */ - public long getStartPosition() { - return mStartPositionMs; - } - - /** - * Return the position in milliseconds at which the playback will end. - * {@link #POSITION_UNKNOWN} means ending at the end of source content. - * @return the position in milliseconds at which the playback will end - */ - public long getEndPosition() { - return mEndPositionMs; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mMetadata, 0); - dest.writeLong(mStartPositionMs); - dest.writeLong(mEndPositionMs); - } - - /** - * Gets the media id for this item. If it's not {@code null}, it's a persistent unique key - * for the underlying media content. - * - * @return media Id from the session - */ - @Nullable String getMediaId() { - synchronized (mLock) { - return mMetadata != null - ? mMetadata.getString(METADATA_KEY_MEDIA_ID) : null; - } - } - - void addOnMetadataChangedListener(Executor executor, OnMetadataChangedListener listener) { - synchronized (mLock) { - for (Pair<OnMetadataChangedListener, Executor> pair : mListeners) { - if (pair.first == listener) { - return; - } - } - mListeners.add(new Pair<>(listener, executor)); - } - } - - void removeOnMetadataChangedListener(OnMetadataChangedListener listener) { - synchronized (mLock) { - for (int i = mListeners.size() - 1; i >= 0; i--) { - if (mListeners.get(i).first == listener) { - mListeners.remove(i); - return; - } - } - } - } - - /** - * Builder for {@link MediaItem2}. - */ - public static final class Builder { - @SuppressWarnings("WeakerAccess") /* synthetic access */ - MediaMetadata mMetadata; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - long mStartPositionMs = 0; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - long mEndPositionMs = POSITION_UNKNOWN; - - /** - * Set the metadata of this instance. {@code null} for unset. - * - * @param metadata metadata - * @return this instance for chaining - */ - public @NonNull Builder setMetadata(@Nullable MediaMetadata metadata) { - mMetadata = metadata; - return this; - } - - /** - * Sets the start position in milliseconds at which the playback will start. - * Any negative number is treated as 0. - * - * @param position the start position in milliseconds at which the playback will start - * @return the same Builder instance. - */ - public @NonNull Builder setStartPosition(long position) { - if (position < 0) { - position = 0; - } - mStartPositionMs = position; - return this; - } - - /** - * Sets the end position in milliseconds at which the playback will end. - * Any negative number is treated as maximum length of the media item. - * - * @param position the end position in milliseconds at which the playback will end - * @return the same Builder instance. - */ - public @NonNull Builder setEndPosition(long position) { - if (position < 0) { - position = POSITION_UNKNOWN; - } - mEndPositionMs = position; - return this; - } - - /** - * Build {@link MediaItem2}. - * - * @return a new {@link MediaItem2}. - */ - public @NonNull MediaItem2 build() { - return new MediaItem2(this); - } - } - - interface OnMetadataChangedListener { - void onMetadataChanged(MediaItem2 item); - } -} diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java index 7f73dc123063..7c752e198f3a 100644 --- a/media/apex/java/android/media/Session2Command.java +++ b/media/apex/java/android/media/Session2Command.java @@ -30,7 +30,7 @@ import java.util.Objects; * <p> * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command. * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and - * {@link #getCustomCommand()} shouldn't be {@code null}. + * {@link #getCustomAction()} shouldn't be {@code null}. * <p> * Refer to the * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a> @@ -63,8 +63,8 @@ public final class Session2Command implements Parcelable { private final int mCommandCode; // Nonnull if it's custom command - private final String mCustomCommand; - private final Bundle mExtras; + private final String mCustomAction; + private final Bundle mCustomExtras; /** * Constructor for creating a command predefined in AndroidX media2. @@ -76,8 +76,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM"); } mCommandCode = commandCode; - mCustomCommand = null; - mExtras = null; + mCustomAction = null; + mCustomExtras = null; } /** @@ -91,8 +91,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("action shouldn't be null"); } mCommandCode = COMMAND_CODE_CUSTOM; - mCustomCommand = action; - mExtras = extras; + mCustomAction = action; + mCustomExtras = extras; } /** @@ -101,8 +101,8 @@ public final class Session2Command implements Parcelable { @SuppressWarnings("WeakerAccess") /* synthetic access */ Session2Command(Parcel in) { mCommandCode = in.readInt(); - mCustomCommand = in.readString(); - mExtras = in.readBundle(); + mCustomAction = in.readString(); + mCustomExtras = in.readBundle(); } /** @@ -118,8 +118,8 @@ public final class Session2Command implements Parcelable { * This will return {@code null} for a predefined command. */ @Nullable - public String getCustomCommand() { - return mCustomCommand; + public String getCustomAction() { + return mCustomAction; } /** @@ -127,8 +127,8 @@ public final class Session2Command implements Parcelable { * This will return {@code null} for a predefined command. */ @Nullable - public Bundle getExtras() { - return mExtras; + public Bundle getCustomExtras() { + return mCustomExtras; } @Override @@ -142,8 +142,8 @@ public final class Session2Command implements Parcelable { throw new IllegalArgumentException("parcel shouldn't be null"); } dest.writeInt(mCommandCode); - dest.writeString(mCustomCommand); - dest.writeBundle(mExtras); + dest.writeString(mCustomAction); + dest.writeBundle(mCustomExtras); } @Override @@ -153,12 +153,12 @@ public final class Session2Command implements Parcelable { } Session2Command other = (Session2Command) obj; return mCommandCode == other.mCommandCode - && TextUtils.equals(mCustomCommand, other.mCustomCommand); + && TextUtils.equals(mCustomAction, other.mCustomAction); } @Override public int hashCode() { - return Objects.hash(mCustomCommand, mCommandCode); + return Objects.hash(mCustomAction, mCommandCode); } /** diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 1ccaa0fe1795..e655460c2ba1 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -535,6 +535,23 @@ public final class AudioAttributes implements Parcelable { } /** + * Return the capture policy. + * @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or + * the default if it was not called. + */ + @CapturePolicy + public int getAllowedCapturePolicy() { + if ((mFlags & FLAG_NO_SYSTEM_CAPTURE) == FLAG_NO_SYSTEM_CAPTURE) { + return ALLOW_CAPTURE_BY_NONE; + } + if ((mFlags & FLAG_NO_MEDIA_PROJECTION) == FLAG_NO_MEDIA_PROJECTION) { + return ALLOW_CAPTURE_BY_SYSTEM; + } + return ALLOW_CAPTURE_BY_ALL; + } + + + /** * Builder class for {@link AudioAttributes} objects. * <p> Here is an example where <code>Builder</code> is used to define the * {@link AudioAttributes} to be used by a new <code>AudioTrack</code> instance: diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java index 3aaa7dfc05d0..ee89509951df 100644 --- a/media/java/android/media/AudioFocusInfo.java +++ b/media/java/android/media/AudioFocusInfo.java @@ -18,6 +18,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,7 @@ import java.util.Objects; * @hide * A class to encapsulate information about an audio focus owner or request. */ +@TestApi @SystemApi public final class AudioFocusInfo implements Parcelable { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 8f699eb9e6fc..d3471378b9d9 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.app.PendingIntent; @@ -1512,7 +1513,22 @@ public class AudioManager { int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); if (result != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); + return; } + mCapturePolicy = capturePolicy; + } + + @AudioAttributes.CapturePolicy + private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; + + /** + * Return the capture policy. + * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or + * the default if it was not called. + */ + @AudioAttributes.CapturePolicy + public int getAllowedCapturePolicy() { + return mCapturePolicy; } //==================================================================== @@ -3035,6 +3051,7 @@ public class AudioManager { * @param requestResult the result to the focus request to be passed to the requester * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull AudioFocusInfo afi, @@ -3074,6 +3091,7 @@ public class AudioManager { * if there was an error sending the request. * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, @@ -3336,6 +3354,7 @@ public class AudioManager { * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission, * {@link #SUCCESS} otherwise. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull AudioPolicy policy) { @@ -3370,6 +3389,7 @@ public class AudioManager { * Unregisters an {@link AudioPolicy} asynchronously. * @param policy the non-null {@link AudioPolicy} to unregister. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { @@ -3396,6 +3416,7 @@ public class AudioManager { * associated with mixes of this policy. * @param policy the non-null {@link AudioPolicy} to unregister. */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { @@ -3410,6 +3431,20 @@ public class AudioManager { } } + /** + * @hide + * @return true if an AudioPolicy was previously registered + */ + @TestApi + public boolean hasRegisteredDynamicPolicy() { + final IAudioService service = getService(); + try { + return service.hasRegisteredDynamicPolicy(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //==================================================================== // Notification of playback activity & playback configuration /** diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java index d61f14c25c7e..fe5005a7cc9a 100644 --- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java +++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java @@ -20,11 +20,14 @@ import android.annotation.NonNull; import android.media.AudioAttributes.AttributeUsage; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioMixingRule; +import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion; import android.media.projection.MediaProjection; import android.os.RemoteException; import com.android.internal.util.Preconditions; +import java.util.function.ToIntFunction; + /** * Configuration for capturing audio played by other apps. * @@ -83,6 +86,39 @@ public final class AudioPlaybackCaptureConfiguration { return mProjection; } + /** @return the usages passed to {@link Builder#addMatchingUsage(int)}. */ + @AttributeUsage + public @NonNull int[] getMatchingUsages() { + return getIntPredicates(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, + criterion -> criterion.getAudioAttributes().getUsage()); + } + + /** @return the UIDs passed to {@link Builder#addMatchingUid(int)}. */ + public @NonNull int[] getMatchingUids() { + return getIntPredicates(AudioMixingRule.RULE_MATCH_UID, + criterion -> criterion.getIntProp()); + } + + /** @return the usages passed to {@link Builder#excludeUsage(int)}. */ + @AttributeUsage + public @NonNull int[] getExcludeUsages() { + return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE, + criterion -> criterion.getAudioAttributes().getUsage()); + } + + /** @return the UIDs passed to {@link Builder#excludeUid(int)}. */ + public @NonNull int[] getExcludeUids() { + return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_UID, + criterion -> criterion.getIntProp()); + } + + private int[] getIntPredicates(int rule, + ToIntFunction<AudioMixMatchCriterion> getPredicate) { + return mAudioMixingRule.getCriteria().stream() + .filter(criterion -> criterion.getRule() == rule) + .mapToInt(getPredicate) + .toArray(); + } /** * Returns a mix that routes audio back into the app while still playing it from the speakers. diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 790e189e9109..d9d614f7ead4 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -975,13 +975,9 @@ public class AudioTrack extends PlayerBase throw new UnsupportedOperationException( "Offload and low latency modes are incompatible"); } - if (mAttributes.getUsage() != AudioAttributes.USAGE_MEDIA) { - throw new UnsupportedOperationException( - "Cannot create AudioTrack, offload requires USAGE_MEDIA"); - } if (!AudioSystem.isOffloadSupported(mFormat, mAttributes)) { throw new UnsupportedOperationException( - "Cannot create AudioTrack, offload format not supported"); + "Cannot create AudioTrack, offload format / attributes not supported"); } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index eddbee46252e..85de00a2a989 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -211,6 +211,8 @@ interface IAudioService { void setVolumePolicy(in VolumePolicy policy); + boolean hasRegisteredDynamicPolicy(); + void registerRecordingCallback(in IRecordingConfigDispatcher rcdb); oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb); diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 09f17c099609..2f03d26830f2 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -19,6 +19,7 @@ package android.media.audiopolicy; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.media.AudioDeviceInfo; import android.media.AudioFormat; @@ -31,6 +32,7 @@ import java.util.Objects; /** * @hide */ +@TestApi @SystemApi public class AudioMix { diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java index 947b06cdf6b2..ed2fdae71fb0 100644 --- a/media/java/android/media/audiopolicy/AudioMixingRule.java +++ b/media/java/android/media/audiopolicy/AudioMixingRule.java @@ -18,6 +18,7 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.media.AudioAttributes; import android.os.Parcel; @@ -41,6 +42,7 @@ import java.util.Objects; * .build(); * </pre> */ +@TestApi @SystemApi public class AudioMixingRule { @@ -92,7 +94,8 @@ public class AudioMixingRule { public static final int RULE_EXCLUDE_UID = RULE_EXCLUSION_MASK | RULE_MATCH_UID; - static final class AudioMixMatchCriterion { + /** @hide */ + public static final class AudioMixMatchCriterion { @UnsupportedAppUsage final AudioAttributes mAttr; @UnsupportedAppUsage @@ -137,6 +140,10 @@ public class AudioMixingRule { dest.writeInt(-1); } } + + public AudioAttributes getAudioAttributes() { return mAttr; } + public int getIntProp() { return mIntProp; } + public int getRule() { return mRule; } } boolean isAffectingUsage(int usage) { @@ -163,7 +170,8 @@ public class AudioMixingRule { int getTargetMixType() { return mTargetMixType; } @UnsupportedAppUsage private final ArrayList<AudioMixMatchCriterion> mCriteria; - ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; } + /** @hide */ + public ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; } @UnsupportedAppUsage private boolean mAllowPrivilegedPlaybackCapture = false; diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 00f601388164..1cd60f78886e 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; @@ -55,6 +56,7 @@ import java.util.List; * @hide * AudioPolicy provides access to the management of audio routing and audio focus. */ +@TestApi @SystemApi public class AudioPolicy { @@ -237,6 +239,7 @@ public class AudioPolicy { } /** + * @hide * Test method to declare whether this audio focus policy is for test purposes only. * Having a test policy registered will disable the current focus policy and replace it * with this test policy. When unregistered, the previous focus policy will be restored. @@ -245,6 +248,7 @@ public class AudioPolicy { * @param isTestFocusPolicy true if the focus policy to register is for testing purposes. * @return the same Builder instance */ + @TestApi @NonNull public Builder setIsTestFocusPolicy(boolean isTestFocusPolicy) { mIsTestFocusPolicy = isTestFocusPolicy; diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt index 239b1d464ea3..eff02d24431e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt +++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt @@ -173,6 +173,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) } override fun draw(c: Canvas) { + c.saveLayer(null, null) unifiedPath.reset() levelPath.reset() levelRect.set(fillRect) @@ -243,6 +244,7 @@ open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) // And draw the plus sign on top of the fill c.drawPath(scaledPlus, errorPaint) } + c.restore() } private fun batteryColorForLevel(level: Int): Int { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index fd557083aefd..1d19fecac8c9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -665,9 +665,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { boolean wasRunning = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING; boolean isRunning = fingerprintRunningState == BIOMETRIC_STATE_RUNNING; mFingerprintRunningState = fingerprintRunningState; - if (DEBUG) Log.v(TAG, "Fingerprint State: " + mFingerprintRunningState); + Log.d(TAG, "fingerprintRunningState: " + mFingerprintRunningState); // Clients of KeyguardUpdateMonitor don't care about the internal state about the - // asynchronousness of the cancel cycle. So only notify them if the actualy running state + // asynchronousness of the cancel cycle. So only notify them if the actually running state // has changed. if (wasRunning != isRunning) { notifyFingerprintRunningStateChanged(); @@ -818,9 +818,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { boolean wasRunning = mFaceRunningState == BIOMETRIC_STATE_RUNNING; boolean isRunning = faceRunningState == BIOMETRIC_STATE_RUNNING; mFaceRunningState = faceRunningState; - if (DEBUG) Log.v(TAG, "Face State: " + mFaceRunningState); + Log.d(TAG, "faceRunningState: " + mFaceRunningState); // Clients of KeyguardUpdateMonitor don't care about the internal state or about the - // asynchronousness of the cancel cycle. So only notify them if the actualy running state + // asynchronousness of the cancel cycle. So only notify them if the actually running state // has changed. if (wasRunning != isRunning) { notifyFaceRunningStateChanged(); @@ -2045,7 +2045,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { */ public void onKeyguardVisibilityChanged(boolean showing) { checkIsHandlerThread(); - if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); + Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); mKeyguardIsVisible = showing; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 329b001a0a7c..6c1d1f91830f 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -180,10 +180,6 @@ public class BatteryMeterView extends LinearLayout implements setClipChildren(false); setClipToPadding(false); Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this); - - // Needed for PorderDuff.Mode.CLEAR operations to work properly, but redraws don't happen - // enough to justify a hardware layer. - setLayerType(LAYER_TYPE_SOFTWARE, null); } private void setupLayoutTransition() { @@ -405,10 +401,10 @@ public class BatteryMeterView extends LinearLayout implements || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) { if (!showing) { mBatteryPercentView = loadPercentView(); - if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); if (mPercentageStyleId != 0) { // Only set if specified as attribute mBatteryPercentView.setTextAppearance(mPercentageStyleId); } + if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); updatePercentText(); addView(mBatteryPercentView, new ViewGroup.LayoutParams( diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 72559f56aaa1..56dbe2b2cd99 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -608,6 +608,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mConnectionCallbacks.add(listener); listener.onConnectionChanged(mOverviewProxy != null); listener.onInteractionFlagsChanged(mInteractionFlags); + listener.onBackButtonAlphaChanged(mBackButtonAlpha, false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index 907b3ad08c8c..85848cafbfcb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -151,7 +151,7 @@ public class NavigationBarController implements Callbacks { ? Dependency.get(AutoHideController.class) : new AutoHideController(context, mHandler); navBar.setAutoHideController(autoHideController); - navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + navBar.restoreSystemUiVisibilityState(); mNavigationBars.append(displayId, navBar); if (result != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index 4ced702f479e..959342b27b56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -141,6 +141,11 @@ public class ButtonDispatcher { public void setVisibility(int visibility) { if (mVisibility == visibility) return; + if (mFadeAnimator != null) { + mFadeAnimator.cancel(); + mFadeAnimator = null; + } + mVisibility = visibility; final int N = mViews.size(); for (int i = 0; i < N; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 9eecdb924448..4d2b56c5e81a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -123,6 +123,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private static final boolean DEBUG = false; private static final String EXTRA_DISABLE_STATE = "disabled_state"; private static final String EXTRA_DISABLE2_STATE = "disabled2_state"; + private static final String EXTRA_SYSTEM_UI_VISIBILITY = "system_ui_visibility"; /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; @@ -156,7 +157,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private Locale mLocale; private int mLayoutDirection; - private int mSystemUiVisibility; + private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE; private LightBarController mLightBarController; private AutoHideController mAutoHideController; @@ -277,6 +278,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (savedInstanceState != null) { mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0); + mSystemUiVisibility = savedInstanceState.getInt(EXTRA_SYSTEM_UI_VISIBILITY, 0); } mAccessibilityManagerWrapper.addCallback(mAccessibilityListener); @@ -363,6 +365,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback super.onSaveInstanceState(outState); outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1); outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2); + outState.putInt(EXTRA_SYSTEM_UI_VISIBILITY, mSystemUiVisibility); if (mNavigationBarView != null) { mNavigationBarView.getLightTransitionsController().saveState(outState); } @@ -492,13 +495,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } } - /** - * Sets System UI flags to {@link NavigationBarFragment}. - * - * @see View#setSystemUiVisibility(int) - */ - public void setSystemUiVisibility(int systemUiVisibility) { - mSystemUiVisibility = systemUiVisibility; + /** Restores the System UI flags saved state to {@link NavigationBarFragment}. */ + public void restoreSystemUiVisibilityState() { final int barMode = computeBarMode(0, mSystemUiVisibility); if (barMode != -1) { mNavigationBarMode = barMode; diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java index 46e3226bb751..7b6a12822faa 100644 --- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -111,6 +111,15 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { + // MotionEventInjector would cancel any injected gesture when any MotionEvent arrives. + // For user using an external device to control the pointer movement, it's almost + // impossible to perform the gestures. Any slightly unintended movement results in the + // cancellation of the gesture. + if ((event.isFromSource(InputDevice.SOURCE_MOUSE) + && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) + && mOpenGesturesInProgress.get(EVENT_SOURCE, false)) { + return; + } cancelAnyPendingInjectedEvents(); sendMotionEventToNext(event, rawEvent, policyFlags); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 757c2dc7f6f1..7f411d83b34b 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -60,8 +60,8 @@ import android.util.SparseBooleanArray; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.ContentCaptureHelper; import android.view.contentcapture.ContentCaptureManager; +import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.IContentCaptureManager; -import android.view.contentcapture.UserDataRemovalRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AbstractRemoteService; @@ -583,14 +583,14 @@ public final class ContentCaptureManagerService extends } @Override - public void removeUserData(@NonNull UserDataRemovalRequest request) { + public void removeData(@NonNull DataRemovalRequest request) { Preconditions.checkNotNull(request); assertCalledByPackageOwner(request.getPackageName()); final int userId = UserHandle.getCallingUserId(); synchronized (mLock) { final ContentCapturePerUserService service = getServiceForUserLocked(userId); - service.removeUserDataLocked(request); + service.removeDataLocked(request); } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 564952697250..b4a1f381f7ff 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -57,7 +57,7 @@ import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import android.view.contentcapture.ContentCaptureCondition; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.WhitelistHelper; @@ -343,12 +343,12 @@ final class ContentCapturePerUserService } @GuardedBy("mLock") - public void removeUserDataLocked(@NonNull UserDataRemovalRequest request) { + public void removeDataLocked(@NonNull DataRemovalRequest request) { if (!isEnabledLocked()) { return; } assertCallerLocked(request.getPackageName()); - mRemoteService.onUserDataRemovalRequest(request); + mRemoteService.onDataRemovalRequest(request); } @GuardedBy("mLock") diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 3fa3fdf6d36e..2171033c5a28 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -29,7 +29,7 @@ import android.service.contentcapture.IContentCaptureServiceCallback; import android.service.contentcapture.SnapshotData; import android.util.Slog; import android.view.contentcapture.ContentCaptureContext; -import android.view.contentcapture.UserDataRemovalRequest; +import android.view.contentcapture.DataRemovalRequest; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.os.IResultReceiver; @@ -120,10 +120,10 @@ final class RemoteContentCaptureService } /** - * Called by {@link ContentCaptureServerSession} to request removal of user data. + * Called by {@link ContentCaptureServerSession} to request removal of content capture data. */ - public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) { - scheduleAsyncRequest((s) -> s.onUserDataRemovalRequest(request)); + public void onDataRemovalRequest(@NonNull DataRemovalRequest request) { + scheduleAsyncRequest((s) -> s.onDataRemovalRequest(request)); } /** diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java index 6018f008054c..5c5b477352b1 100644 --- a/services/core/java/com/android/server/BluetoothService.java +++ b/services/core/java/com/android/server/BluetoothService.java @@ -18,11 +18,10 @@ package com.android.server; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.os.SystemProperties; -class BluetoothService extends SystemService { - private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless"; +import com.android.internal.os.RoSystemProperties; +class BluetoothService extends SystemService { private BluetoothManagerService mBluetoothManagerService; private boolean mInitialized = false; @@ -48,7 +47,7 @@ class BluetoothService extends SystemService { publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, mBluetoothManagerService); } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY && - !SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false)) { + !RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) { initialize(); } } diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 3dbea0d1978e..411dd794d1bd 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -17,7 +17,6 @@ package com.android.server.attention; import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; -import static android.provider.Settings.System.ADAPTIVE_SLEEP; import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED; import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; @@ -47,7 +46,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; -import android.provider.Settings; import android.service.attention.AttentionService; import android.service.attention.AttentionService.AttentionFailureCodes; import android.service.attention.AttentionService.AttentionSuccessCodes; @@ -275,19 +273,6 @@ public class AttentionManagerService extends SystemService { } } - /** Disables service dependants. */ - private void disableSelf() { - final long identity = Binder.clearCallingIdentity(); - try { - if (DEBUG) { - Slog.d(LOG_TAG, "Disabling self."); - } - Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - @GuardedBy("mLock") private void freeIfInactiveLocked() { // If we are called here, it means someone used the API again - reset the timer then. @@ -418,11 +403,6 @@ public class AttentionManagerService extends SystemService { public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) { AttentionManagerService.this.cancelAttentionCheck(callbackInternal); } - - @Override - public void disableSelf() { - AttentionManagerService.this.disableSelf(); - } } private static final class AttentionCheckCache { diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index b7746477f0f8..44c1715cfed5 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -406,6 +406,10 @@ import java.util.ArrayList; mAudioService.checkVolumeCecOnHdmiConnection(state, caller); } + /*package*/ boolean hasAudioFocusUsers() { + return mAudioService.hasAudioFocusUsers(); + } + //--------------------------------------------------------------------- // Message handling on behalf of helper classes /*package*/ void postBroadcastScoConnectionState(int state) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 7750bfefae05..91b51b4989d8 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -819,11 +819,12 @@ public final class AudioDeviceInventory { if (((device == musicDevice) || mDeviceBroker.isInCommunication()) && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy() && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) { - if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)) { + if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/) + && !mDeviceBroker.hasAudioFocusUsers()) { // no media playback, not a "becoming noisy" situation, otherwise it could cause // the pausing of some apps that are playing remotely AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( - "dropping ACTION_AUDIO_BECOMING_NOISY, no media playback")).printLog(TAG)); + "dropping ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); return 0; } mDeviceBroker.postBroadcastBecomingNoisy(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 77472ed288c3..aee08bb09401 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1523,9 +1523,11 @@ public class AudioService extends IAudioService.Stub + ", flags=" + flags + ", caller=" + caller + ", volControlStream=" + mVolumeControlStream + ", userSelect=" + mUserSelectedVolumeControlStream); - sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, - direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) - .append("/").append(caller).append(" uid:").append(uid).toString())); + if (direction != AudioManager.ADJUST_SAME) { + sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType, + direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) + .append("/").append(caller).append(" uid:").append(uid).toString())); + } final int streamType; synchronized (mForceControlStreamLock) { // Request lock in case mVolumeControlStream is changed by other thread. @@ -5578,6 +5580,10 @@ public class AudioService extends IAudioService.Stub return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr); } + /*package*/ boolean hasAudioFocusUsers() { + return mMediaFocusControl.hasAudioFocusUsers(); + } + //========================================================================================== private boolean readCameraSoundForced() { return SystemProperties.getBoolean("audio.camerasound.force", false) || @@ -6320,6 +6326,11 @@ public class AudioService extends IAudioService.Stub @Override public void adjustStreamVolumeForUid(int streamType, int direction, int flags, String callingPackage, int uid) { + if (direction != AudioManager.ADJUST_SAME) { + sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_VOL_UID, streamType, + direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage) + .append(" uid:").append(uid).toString())); + } adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid); } @@ -6660,6 +6671,13 @@ public class AudioService extends IAudioService.Stub return AudioManager.SUCCESS; } + /** see AudioManager.hasRegisteredDynamicPolicy */ + public boolean hasRegisteredDynamicPolicy() { + synchronized (mAudioPolicies) { + return !mAudioPolicies.isEmpty(); + } + } + private final Object mExtVolumeControllerLock = new Object(); private IAudioPolicyCallback mExtVolumeController; private void setExtVolumeController(IAudioPolicyCallback apc) { diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java index 7ccb45e97912..d999217bf29b 100644 --- a/services/core/java/com/android/server/audio/AudioServiceEvents.java +++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java @@ -94,6 +94,7 @@ public class AudioServiceEvents { static final int VOL_SET_STREAM_VOL = 2; static final int VOL_SET_HEARING_AID_VOL = 3; static final int VOL_SET_AVRCP_VOL = 4; + static final int VOL_ADJUST_VOL_UID = 5; final int mOp; final int mStream; @@ -160,6 +161,13 @@ public class AudioServiceEvents { return new StringBuilder("setAvrcpVolume:") .append(" index:").append(mVal1) .toString(); + case VOL_ADJUST_VOL_UID: + return new StringBuilder("adjustStreamVolumeForUid(stream:") + .append(AudioSystem.streamToString(mStream)) + .append(" dir:").append(AudioManager.adjustToString(mVal1)) + .append(" flags:0x").append(Integer.toHexString(mVal2)) + .append(") from ").append(mCaller) + .toString(); default: return new StringBuilder("FIXME invalid op:").append(mOp).toString(); } } diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 1e58b454a15b..5c93071fd551 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -162,6 +162,12 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } + /*package*/ boolean hasAudioFocusUsers() { + synchronized (mAudioFocusLock) { + return !mFocusStack.empty(); + } + } + /** * Discard the current audio focus owner. * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e88d62f58507..3c97c39f70a0 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4710,10 +4710,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @ShellCommandResult private int handleShellCommandEnableDisableInputMethod( @NonNull ShellCommand shellCommand, boolean enabled) { + final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); final String imeId = shellCommand.getNextArgRequired(); final PrintWriter out = shellCommand.getOutPrintWriter(); final PrintWriter error = shellCommand.getErrPrintWriter(); - final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); synchronized (mMethodMap) { final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved, mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter()); @@ -4733,6 +4733,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * * <p>You cannot use this helper method if the command has other options.</p> * + * <p>CAVEAT: This method must be called only once before any other + * {@link ShellCommand#getNextArg()} and {@link ShellCommand#getNextArgRequired()} for the + * main arguments.</p> + * * @param shellCommand {@link ShellCommand} from which options should be obtained. * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified. */ @@ -4819,10 +4823,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @ShellCommandResult private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) { + final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); final String imeId = shellCommand.getNextArgRequired(); final PrintWriter out = shellCommand.getOutPrintWriter(); final PrintWriter error = shellCommand.getErrPrintWriter(); - final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand); synchronized (mMethodMap) { final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved, mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter()); @@ -4864,7 +4868,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub out.print("Input method "); out.print(imeId); out.print(" selected for user #"); - error.println(userId); + out.println(userId); } } } diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index a2515c8bb8cc..580150ed887e 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -1228,6 +1228,24 @@ public final class MultiClientInputMethodManagerService { public boolean isUidAllowedOnDisplay(int displayId, int uid) { return mIWindowManagerInternal.isUidAllowedOnDisplay(displayId, uid); } + + @BinderThread + @Override + public void setActive(int clientId, boolean active) { + synchronized (mPerUserData.mLock) { + final InputMethodClientInfo clientInfo = + mPerUserData.getClientFromIdLocked(clientId); + if (clientInfo == null) { + Slog.e(TAG, "Unknown clientId=" + clientId); + return; + } + try { + clientInfo.mClient.setActive(active, false /* fullscreen */); + } catch (RemoteException e) { + return; + } + } + } } /** diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java index 686ae2bbaede..5cbd237a0722 100644 --- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java +++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java @@ -52,10 +52,12 @@ public class PasswordSlotManager { // This maps each used password slot to the OS image that created it. Password slots are // integer keys/indices into secure storage. The OS image is recorded as a string. The factory // image is "host" and GSIs are "gsi<N>" where N >= 1. - private final Map<Integer, String> mSlotMap; + private Map<Integer, String> mSlotMap; + + // Cache the active slots until loadSlotMap() is called. + private Set<Integer> mActiveSlots; public PasswordSlotManager() { - mSlotMap = loadSlotMap(); } @VisibleForTesting @@ -74,6 +76,11 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void refreshActiveSlots(Set<Integer> activeSlots) throws RuntimeException { + if (mSlotMap == null) { + mActiveSlots = new HashSet<Integer>(activeSlots); + return; + } + // Update which slots are owned by the current image. final HashSet<Integer> slotsToDelete = new HashSet<Integer>(); for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { @@ -100,6 +107,7 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void markSlotInUse(int slot) throws RuntimeException { + ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) { throw new RuntimeException("password slot " + slot + " is not available"); } @@ -113,6 +121,7 @@ public class PasswordSlotManager { * @throws RuntimeException */ public void markSlotDeleted(int slot) throws RuntimeException { + ensureSlotMapLoaded(); if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) { throw new RuntimeException("password slot " + slot + " cannot be deleted"); } @@ -126,6 +135,7 @@ public class PasswordSlotManager { * @return Integer set of all used slots. */ public Set<Integer> getUsedSlots() { + ensureSlotMapLoaded(); return Collections.unmodifiableSet(mSlotMap.keySet()); } @@ -167,8 +177,21 @@ public class PasswordSlotManager { return new HashMap<Integer, String>(); } + private void ensureSlotMapLoaded() { + if (mSlotMap == null) { + mSlotMap = loadSlotMap(); + if (mActiveSlots != null) { + refreshActiveSlots(mActiveSlots); + mActiveSlots = null; + } + } + } + @VisibleForTesting protected void saveSlotMap(OutputStream stream) throws IOException { + if (mSlotMap == null) { + return; + } final Properties props = new Properties(); for (Map.Entry<Integer, String> entry : mSlotMap.entrySet()) { props.setProperty(entry.getKey().toString(), entry.getValue()); @@ -177,6 +200,9 @@ public class PasswordSlotManager { } private void saveSlotMap() { + if (mSlotMap == null) { + return; + } if (!getSlotMapFile().getParentFile().exists()) { Slog.w(TAG, "Not saving slot map, " + getSlotMapDir() + " does not exist"); return; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ee2e4f573fb9..7f1b25ca3ca3 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -455,7 +455,6 @@ public class NotificationManagerService extends SystemService { private int mAutoGroupAtCount; private boolean mIsTelevision; private boolean mIsAutomotive; - private boolean mNotificationEffectsEnabledForAutomotive; private MetricsLogger mMetricsLogger; private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; @@ -1687,8 +1686,6 @@ public class NotificationManagerService extends SystemService { mIsAutomotive = mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0); - mNotificationEffectsEnabledForAutomotive = - resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive); mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( com.android.internal.R.array.config_nonBlockableNotificationPackages)); @@ -5563,9 +5560,6 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting @GuardedBy("mNotificationLock") void buzzBeepBlinkLocked(NotificationRecord record) { - if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) { - return; - } boolean buzz = false; boolean beep = false; boolean blink = false; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c1587dc9f86f..c12ee03fb86d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -19151,22 +19151,22 @@ public class PackageManagerService extends IPackageManager.Stub final UserHandle user = action.user; final int flags = action.flags; final boolean systemApp = isSystemApp(ps); - synchronized (mPackages) { - if (ps.parentPackageName != null - && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { - if (DEBUG_REMOVE) { - Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" - + ((user == null) ? UserHandle.USER_ALL : user)); - } - final int removedUserId = (user != null) ? user.getIdentifier() - : UserHandle.USER_ALL; + if (ps.parentPackageName != null + && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { + if (DEBUG_REMOVE) { + Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" + + ((user == null) ? UserHandle.USER_ALL : user)); + } + final int removedUserId = (user != null) ? user.getIdentifier() + : UserHandle.USER_ALL; - clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); + clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); + synchronized (mPackages) { markPackageUninstalledForUserLPw(ps, user); scheduleWritePackageRestrictionsLocked(user); - return; } + return; } final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); @@ -19180,6 +19180,7 @@ public class PackageManagerService extends IPackageManager.Stub // its data. If this is a system app, we only allow this to happen if // they have set the special DELETE_SYSTEM_APP which requests different // semantics than normal for uninstalling system apps. + final boolean clearPackageStateAndReturn; synchronized (mPackages) { markPackageUninstalledForUserLPw(ps, user); if (!systemApp) { @@ -19190,15 +19191,14 @@ public class PackageManagerService extends IPackageManager.Stub // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users"); - clearPackageStateForUserLIF(ps, userId, outInfo, flags); - scheduleWritePackageRestrictionsLocked(user); - return; + clearPackageStateAndReturn = true; } else { // We need to set it back to 'installed' so the uninstall // broadcasts will be sent correctly. if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete"); ps.setInstalled(true, userId); mSettings.writeKernelMappingLPr(ps); + clearPackageStateAndReturn = false; } } else { // This is a system app, so we assume that the @@ -19206,10 +19206,15 @@ public class PackageManagerService extends IPackageManager.Stub // we need to do is clear this user's data and save that // it is uninstalled. if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app"); - clearPackageStateForUserLIF(ps, userId, outInfo, flags); + clearPackageStateAndReturn = true; + } + } + if (clearPackageStateAndReturn) { + clearPackageStateForUserLIF(ps, userId, outInfo, flags); + synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(user); - return; } + return; } } @@ -20027,7 +20032,7 @@ public class PackageManagerService extends IPackageManager.Stub PreferredActivity pa = removed.get(j); pir.removeFilter(pa); } - outUserChanged.setValueAt(thisUserId, true); + outUserChanged.put(thisUserId, true); } } } @@ -20747,8 +20752,16 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public String getAttentionServicePackageName() { - return mContext.getString(R.string.config_defaultAttentionService); + public @Nullable String getAttentionServicePackageName() { + final String flattenedComponentName = + mContext.getString(R.string.config_defaultAttentionService); + if (flattenedComponentName != null) { + ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName); + if (componentName != null && componentName.getPackageName() != null) { + return componentName.getPackageName(); + } + } + return null; } private @Nullable String getDocumenterPackageName() { diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 72d543862c58..803ab2d299e2 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -261,13 +261,13 @@ public class StagingManager { if (storageManager.supportsCheckpoint()) { storageManager.startCheckpoint(1 /* numRetries */); } - } catch (RemoteException e) { + } catch (Exception e) { // TODO(b/130190815) make a RemoteException again // While StorageManager lives in the same process, the native implementation // it calls through lives in 'vold'; so, this call can fail if 'vold' isn't // reachable. // Since we can live without filesystem checkpointing, just warn in this case // and continue. - Slog.w(TAG, "Could not start filesystem checkpoint."); + Slog.w(TAG, "Could not start filesystem checkpoint:", e); } session.setStagedSessionReady(); diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index d9d21babe210..5e829b2d6067 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -16,9 +16,14 @@ package com.android.server.power; +import static android.provider.Settings.System.ADAPTIVE_SLEEP; + +import android.Manifest; import android.attention.AttentionManagerInternal; import android.attention.AttentionManagerInternal.AttentionCallbackInternal; +import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.os.Handler; import android.os.PowerManager; @@ -83,6 +88,12 @@ public class AttentionDetector { @VisibleForTesting protected AttentionManagerInternal mAttentionManager; + @VisibleForTesting + protected PackageManager mPackageManager; + + @VisibleForTesting + protected ContentResolver mContentResolver; + /** * Current wakefulness of the device. {@see PowerManagerInternal} */ @@ -137,6 +148,8 @@ public class AttentionDetector { public void systemReady(Context context) { updateEnabledFromSettings(context); + mPackageManager = context.getPackageManager(); + mContentResolver = context.getContentResolver(); mAttentionManager = LocalServices.getService(AttentionManagerInternal.class); mMaximumExtensionMillis = context.getResources().getInteger( com.android.internal.R.integer.config_attentionMaximumExtension); @@ -162,6 +175,11 @@ public class AttentionDetector { return nextScreenDimming; } + if (!serviceHasSufficientPermissions()) { + Settings.System.putInt(mContentResolver, ADAPTIVE_SLEEP, 0); + return nextScreenDimming; + } + final long now = SystemClock.uptimeMillis(); final long whenToCheck = nextScreenDimming - getAttentionTimeout(); final long whenToStopExtending = mLastUserActivityTime + mMaximumExtensionMillis; @@ -263,6 +281,18 @@ public class AttentionDetector { return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported(); } + /** + * Returns {@code true} if the attention service has sufficient permissions, disables the + * depending features otherwise. + */ + @VisibleForTesting + boolean serviceHasSufficientPermissions() { + final String attentionPackage = mPackageManager.getAttentionServicePackageName(); + return attentionPackage != null && mPackageManager.checkPermission( + Manifest.permission.CAMERA, attentionPackage) + == PackageManager.PERMISSION_GRANTED; + } + public void dump(PrintWriter pw) { pw.print("AttentionDetector:"); pw.print(" mMaximumExtensionMillis=" + mMaximumExtensionMillis); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 10ed88f49231..44ed070fda23 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -2084,6 +2084,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId) != 0); + e.writeBoolean(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, + userId) != 0); pulledData.add(e); } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index b287a0b011e7..7eac07c47741 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -457,7 +457,7 @@ public class ActivityStartController { "pendingActivityLaunch"); try { starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, - resume, pal.r.pendingOptions, null, null /* outRecords */); + resume, pal.r.pendingOptions, null); } catch (Exception e) { Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); pal.sendErrorResult(e.getMessage()); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 473a8757f09f..ea9477f7bbc4 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -544,11 +544,17 @@ class ActivityStarter { */ int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, - int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, - ActivityRecord[] outActivity) { + int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) { try { - return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, - doResume, options, inTask, outActivity); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent); + mLastStartReason = "startResolvedActivity"; + mLastStartActivityTimeMs = System.currentTimeMillis(); + mLastStartActivityRecord[0] = r; + mLastStartActivityResult = startActivity(r, sourceRecord, voiceSession, voiceInteractor, + startFlags, doResume, options, inTask, mLastStartActivityRecord); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult, + mLastStartActivityRecord[0]); + return mLastStartActivityResult; } finally { onExecutionComplete(); } @@ -937,7 +943,7 @@ class ActivityStarter { || callingUid == Process.NFC_UID) { return false; } - // don't abort if the callingUid is in the foreground or is a persistent system process + // don't abort if the callingUid has a visible window or is a persistent system process final int callingUidProcState = mService.getUidState(callingUid); final boolean callingUidHasAnyVisibleWindow = mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid); @@ -946,7 +952,7 @@ class ActivityStarter { || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP; final boolean isCallingUidPersistentSystemProcess = (callingUid == Process.SYSTEM_UID) || callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; - if (isCallingUidForeground || isCallingUidPersistentSystemProcess) { + if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) { return false; } // take realCallingUid into consideration @@ -965,8 +971,8 @@ class ActivityStarter { : (realCallingUid == Process.SYSTEM_UID) || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI; if (realCallingUid != callingUid) { - // don't abort if the realCallingUid is in the foreground and callingUid isn't - if (isRealCallingUidForeground) { + // don't abort if the realCallingUid has a visible window + if (realCallingUidHasAnyVisibleWindow) { return false; } // if the realCallingUid is a persistent system process, abort if the IntentSender @@ -980,35 +986,6 @@ class ActivityStarter { return false; } } - // If we don't have callerApp at this point, no caller was provided to startActivity(). - // That's the case for PendingIntent-based starts, since the creator's process might not be - // up and alive. If that's the case, we retrieve the WindowProcessController for the send() - // caller, so that we can make the decision based on its foreground/whitelisted state. - if (callerApp == null) { - callerApp = mService.getProcessController(realCallingPid, realCallingUid); - } - if (callerApp != null) { - // don't abort if the callerApp has any visible activity - if (callerApp.hasForegroundActivities()) { - return false; - } - // don't abort if the callerApp is instrumenting with background activity starts privs - if (callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) { - return false; - } - // don't abort if the caller is currently temporarily whitelisted - if (callerApp.areBackgroundActivityStartsAllowed()) { - return false; - } - // don't abort if the caller has an activity in any foreground task - if (callerApp.hasActivityInVisibleTask()) { - return false; - } - // don't abort if the caller is bound by a UID that's currently foreground - if (isBoundByForegroundUid(callerApp)) { - return false; - } - } // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) == PERMISSION_GRANTED) { @@ -1033,6 +1010,33 @@ class ActivityStarter { + " temporarily whitelisted. This will not be supported in future Q builds."); return false; } + // If we don't have callerApp at this point, no caller was provided to startActivity(). + // That's the case for PendingIntent-based starts, since the creator's process might not be + // up and alive. If that's the case, we retrieve the WindowProcessController for the send() + // caller, so that we can make the decision based on its foreground/whitelisted state. + int callerAppUid = callingUid; + if (callerApp == null) { + callerApp = mService.getProcessController(realCallingPid, realCallingUid); + callerAppUid = realCallingUid; + } + // don't abort if the callerApp or other processes of that uid are whitelisted in any way + if (callerApp != null) { + // first check the original calling process + if (callerApp.areBackgroundActivityStartsAllowed()) { + return false; + } + // only if that one wasn't whitelisted, check the other ones + final ArraySet<WindowProcessController> uidProcesses = + mService.mProcessMap.getProcesses(callerAppUid); + if (uidProcesses != null) { + for (int i = uidProcesses.size() - 1; i >= 0; i--) { + final WindowProcessController proc = uidProcesses.valueAt(i); + if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) { + return false; + } + } + } + } // anything that has fallen through would currently be aborted Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid @@ -1057,18 +1061,6 @@ class ActivityStarter { return true; } - private boolean isBoundByForegroundUid(WindowProcessController callerApp) { - final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids(); - for (int i = boundClientUids.size() - 1; i >= 0; --i) { - final int uid = boundClientUids.valueAt(i); - if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid) - || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) { - return true; - } - } - return false; - } - // TODO: remove this toast after feature development is done void showBackgroundActivityBlockedToast(boolean abort, String callingPackage) { final Resources res = mService.mContext.getResources(); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d25466bf348..48aee200ccc0 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -503,7 +503,7 @@ public abstract class ActivityTaskManagerInternal { public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution); - /** Returns true if uid has a visible window or its process is in a top state. */ + /** Returns true if uid is considered foreground for activity start purposes. */ public abstract boolean isUidForeground(int uid); /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index b4249046c1b5..3fa026873953 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -373,8 +373,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>(); /** All processes currently running that might have a window organized by name. */ final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>(); - /** All processes we currently have running mapped by pid */ - final SparseArray<WindowProcessController> mPidMap = new SparseArray<>(); + /** All processes we currently have running mapped by pid and uid */ + final WindowProcessControllerMap mProcessMap = new WindowProcessControllerMap(); /** This is the process holding what we currently consider to be the "home" activity. */ WindowProcessController mHomeProcess; /** The currently running heavy-weight process, if any. */ @@ -913,7 +913,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return getGlobalConfiguration(); } synchronized (mGlobalLock) { - final WindowProcessController app = mPidMap.get(pid); + final WindowProcessController app = mProcessMap.getProcess(pid); return app != null ? app.getConfiguration() : getGlobalConfiguration(); } } @@ -4640,7 +4640,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { enforceSystemHasVrFeature(); synchronized (mGlobalLock) { final int pid = Binder.getCallingPid(); - final WindowProcessController wpc = mPidMap.get(pid); + final WindowProcessController wpc = mProcessMap.getProcess(pid); mVrController.setVrThreadLocked(tid, pid, wpc); } } @@ -4659,7 +4659,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { enforceSystemHasVrFeature(); synchronized (mGlobalLock) { final int pid = Binder.getCallingPid(); - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); mVrController.setPersistentVrThreadLocked(tid, pid, proc); } } @@ -5204,9 +5204,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.sendMessage(msg); } - for (int i = mPidMap.size() - 1; i >= 0; i--) { - final int pid = mPidMap.keyAt(i); - final WindowProcessController app = mPidMap.get(pid); + SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap(); + for (int i = pidMap.size() - 1; i >= 0; i--) { + final int pid = pidMap.keyAt(i); + final WindowProcessController app = pidMap.get(pid); if (DEBUG_CONFIGURATION) { Slog.v(TAG_CONFIGURATION, "Update process config of " + app.mName + " to new config " + configCopy); @@ -5859,7 +5860,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } WindowProcessController getProcessController(int pid, int uid) { - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); if (proc == null) return null; if (UserHandle.isApp(uid) && proc.mUid == uid) { return proc; @@ -5872,8 +5873,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } boolean isUidForeground(int uid) { - return (getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) - || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); + // A uid is considered to be foreground if it has a visible non-toast window. + return mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid); } boolean isDeviceOwner(int uid) { @@ -6423,14 +6424,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void onProcessMapped(int pid, WindowProcessController proc) { synchronized (mGlobalLock) { - mPidMap.put(pid, proc); + mProcessMap.put(pid, proc); } } @Override public void onProcessUnMapped(int pid) { synchronized (mGlobalLock) { - mPidMap.remove(pid); + mProcessMap.remove(pid); } } @@ -6480,9 +6481,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ @Override public void onImeWindowSetOnDisplay(final int pid, final int displayId) { - // Update display configuration for IME process only when Single-client IME window - // moving to another display. - if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return; + // Don't update process-level configuration for Multi-Client IME process since other + // IMEs on other displays will also receive this configuration change due to IME + // services use the same application config/context. + if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) return; if (pid == MY_PID || pid < 0) { if (DEBUG_CONFIGURATION) { @@ -6502,7 +6504,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } return; } - final WindowProcessController process = mPidMap.get(pid); + final WindowProcessController process = mProcessMap.getProcess(pid); if (process == null) { if (DEBUG_CONFIGURATION) { Slog.w(TAG, "Trying to update display configuration for invalid " @@ -6695,7 +6697,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // Only allow this from foreground processes, so that background // applications can't abuse it to prevent system UI from being shown. if (uid >= FIRST_APPLICATION_UID) { - final WindowProcessController proc = mPidMap.get(pid); + final WindowProcessController proc = mProcessMap.getProcess(pid); if (!proc.isPerceptible()) { Slog.w(TAG, "Ignoring closeSystemDialogs " + reason + " from background process " + proc); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index c8f8e82bdb18..104805fba308 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -48,6 +48,7 @@ import android.os.Message; import android.os.RemoteException; import android.util.AtomicFile; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; public final class CompatModePackages { @@ -324,8 +325,9 @@ public final class CompatModePackages { ActivityRecord starting = stack.restartPackage(packageName); // Tell all processes that loaded this package about the change. - for (int i = mService.mPidMap.size() - 1; i >= 0; i--) { - final WindowProcessController app = mService.mPidMap.valueAt(i); + SparseArray<WindowProcessController> pidMap = mService.mProcessMap.getPidMap(); + for (int i = pidMap.size() - 1; i >= 0; i--) { + final WindowProcessController app = pidMap.valueAt(i); if (!app.mPkgList.contains(packageName)) { continue; } diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index 4bd8cab05700..a7a793fa8d34 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -41,7 +41,7 @@ class Dimmer { private static final int DEFAULT_DIM_ANIM_DURATION = 200; private class DimAnimatable implements SurfaceAnimator.Animatable { - private final SurfaceControl mDimLayer; + private SurfaceControl mDimLayer; private DimAnimatable(SurfaceControl dimLayer) { mDimLayer = dimLayer; @@ -100,6 +100,11 @@ class Dimmer { // See getSurfaceWidth() above for explanation. return mHost.getSurfaceHeight(); } + + void removeSurface() { + getPendingTransaction().remove(mDimLayer); + mDimLayer = null; + } } @VisibleForTesting @@ -129,8 +134,7 @@ class Dimmer { final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> { if (!mDimming) { - dimAnimatable.getPendingTransaction().remove(mDimLayer); - mDimLayer = null; + dimAnimatable.removeSurface(); } }, mHost.mWmService); } diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java index 3d20501222b6..d774dc3fd2f1 100644 --- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java @@ -90,8 +90,6 @@ public class ImmersiveModeConfirmation { mShowDelayMs = getNavBarExitDuration() * 3; mPanicThresholdMs = context.getResources() .getInteger(R.integer.config_immersive_mode_confirmation_panic); - mWindowManager = (WindowManager) - mContext.getSystemService(Context.WINDOW_SERVICE); mVrModeEnabled = vrModeEnabled; } @@ -177,7 +175,7 @@ public class ImmersiveModeConfirmation { private void handleHide() { if (mClingWindow != null) { if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); - mWindowManager.removeView(mClingWindow); + getWindowManager().removeView(mClingWindow); mClingWindow = null; } } @@ -275,7 +273,7 @@ public class ImmersiveModeConfirmation { super.onAttachedToWindow(); DisplayMetrics metrics = new DisplayMetrics(); - mWindowManager.getDefaultDisplay().getMetrics(metrics); + getWindowManager().getDefaultDisplay().getMetrics(metrics); float density = metrics.density; getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener); @@ -341,6 +339,19 @@ public class ImmersiveModeConfirmation { } } + /** + * DO HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD + * The reason why we add this method is to avoid the deadlock of WMG->WMS and WMS->WMG + * when ImmersiveModeConfirmation object is created. + */ + private WindowManager getWindowManager() { + if (mWindowManager == null) { + mWindowManager = (WindowManager) + mContext.getSystemService(Context.WINDOW_SERVICE); + } + return mWindowManager; + } + private void handleShow() { if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation"); @@ -352,7 +363,7 @@ public class ImmersiveModeConfirmation { // show the confirmation WindowManager.LayoutParams lp = getClingWindowLayoutParams(); - mWindowManager.addView(mClingWindow, lp); + getWindowManager().addView(mClingWindow, lp); } private final Runnable mConfirm = new Runnable() { diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index d6c7b21e16b2..7dcbedf811c2 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -60,7 +60,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; @@ -185,7 +184,6 @@ class RecentTasks { // front. Newly created tasks, or tasks that are removed from the list will continue to change // the list. This does not affect affiliated tasks. private boolean mFreezeTaskListReordering; - private long mFreezeTaskListReorderingTime; private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS; // Mainly to avoid object recreation on multiple calls. @@ -220,6 +218,9 @@ class RecentTasks { } }; + private final Runnable mResetFreezeTaskListOnTimeoutRunnable = + this::resetFreezeTaskListReorderingOnTimeout; + @VisibleForTesting RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { mService = service; @@ -255,8 +256,7 @@ class RecentTasks { } @VisibleForTesting - void setFreezeTaskListTimeoutParams(long reorderingTime, long timeoutMs) { - mFreezeTaskListReorderingTime = reorderingTime; + void setFreezeTaskListTimeout(long timeoutMs) { mFreezeTaskListTimeoutMs = timeoutMs; } @@ -272,7 +272,8 @@ class RecentTasks { // Always update the reordering time when this is called to ensure that the timeout // is reset mFreezeTaskListReordering = true; - mFreezeTaskListReorderingTime = SystemClock.elapsedRealtime(); + mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable); + mService.mH.postDelayed(mResetFreezeTaskListOnTimeoutRunnable, mFreezeTaskListTimeoutMs); } /** @@ -286,6 +287,7 @@ class RecentTasks { // Once we end freezing the task list, reset the existing task order to the stable state mFreezeTaskListReordering = false; + mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable); // If the top task is provided, then restore the top task to the front of the list if (topTask != null) { @@ -295,6 +297,8 @@ class RecentTasks { // Resume trimming tasks trimInactiveRecentTasks(); + + mService.getTaskChangeNotificationController().notifyTaskStackChanged(); } /** @@ -302,13 +306,8 @@ class RecentTasks { * before we need to iterate the task list in order (either for purposes of returning the list * to SystemUI or if we need to trim tasks in order) */ + @VisibleForTesting void resetFreezeTaskListReorderingOnTimeout() { - // Unfreeze the recent task list if the time heuristic has passed - if (mFreezeTaskListReorderingTime - > (SystemClock.elapsedRealtime() - mFreezeTaskListTimeoutMs)) { - return; - } - final ActivityStack focusedStack = mService.getTopDisplayFocusedStack(); final TaskRecord topTask = focusedStack != null ? focusedStack.topTask() @@ -875,9 +874,6 @@ class RecentTasks { final Set<Integer> includedUsers = getProfileIds(userId); includedUsers.add(Integer.valueOf(userId)); - // Check if the frozen task list has timed out - resetFreezeTaskListReorderingOnTimeout(); - final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>(); final int size = mTasks.size(); int numVisibleTasks = 0; @@ -1654,8 +1650,8 @@ class RecentTasks { pw.println("mRecentsUid=" + mRecentsUid); pw.println("mRecentsComponent=" + mRecentsComponent); pw.println("mFreezeTaskListReordering=" + mFreezeTaskListReordering); - pw.println("mFreezeTaskListReorderingTime (time since)=" - + (SystemClock.elapsedRealtime() - mFreezeTaskListReorderingTime) + "ms"); + pw.println("mFreezeTaskListReorderingPendingTimeout=" + + mService.mH.hasCallbacks(mResetFreezeTaskListOnTimeoutRunnable)); if (mTasks.isEmpty()) { return; } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1ca31f127b0d..f9fd54178ca7 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -314,9 +314,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> * Returns true if the callingUid has any non-toast window currently visible to the user. */ boolean isAnyNonToastWindowVisibleForUid(int callingUid) { - return forAllWindows(w -> { - return w.getOwningUid() == callingUid && w.isVisible() && w.mAttrs.type != TYPE_TOAST; - }, true /* traverseTopToBottom */); + return forAllWindows(w -> + w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST + && w.isVisibleNow(), + true /* traverseTopToBottom */); } /** diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 33d952e80a6b..b3b41b733cdb 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -286,8 +286,12 @@ class SurfaceAnimator { final boolean destroy = mLeash != null && surface != null && parent != null; if (destroy) { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent"); - t.reparent(surface, parent); - scheduleAnim = true; + // We shouldn't really need these isValid checks but we do + // b/130364451 + if (surface.isValid() && parent.isValid()) { + t.reparent(surface, parent); + scheduleAnim = true; + } } mService.mAnimationTransferMap.remove(mAnimation); if (mLeash != null && destroyLeash) { diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 4ca35f7d427b..eb919eb00f0c 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -372,16 +372,37 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mAllowBackgroundActivityStarts = allowBackgroundActivityStarts; } - public boolean areBackgroundActivityStartsAllowed() { - return mAllowBackgroundActivityStarts; + boolean areBackgroundActivityStartsAllowed() { + // allow if the whitelisting flag was explicitly set + if (mAllowBackgroundActivityStarts) { + return true; + } + // allow if the proc is instrumenting with background activity starts privs + if (mInstrumentingWithBackgroundActivityStartPrivileges) { + return true; + } + // allow if the caller has an activity in any foreground task + if (hasActivityInVisibleTask()) { + return true; + } + // allow if the caller is bound by a UID that's currently foreground + if (isBoundByForegroundUid()) { + return true; + } + return false; } - public void setBoundClientUids(ArraySet<Integer> boundClientUids) { - mBoundClientUids = boundClientUids; + private boolean isBoundByForegroundUid() { + for (int i = mBoundClientUids.size() - 1; i >= 0; --i) { + if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) { + return true; + } + } + return false; } - public ArraySet<Integer> getBoundClientUids() { - return mBoundClientUids; + public void setBoundClientUids(ArraySet<Integer> boundClientUids) { + mBoundClientUids = boundClientUids; } public void setInstrumenting(boolean instrumenting, @@ -394,14 +415,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return mInstrumenting; } - /** - * @return true if the instrumentation was started by a holder of - * START_ACTIVITIES_FROM_BACKGROUND permission - */ - boolean isInstrumentingWithBackgroundActivityStartPrivileges() { - return mInstrumentingWithBackgroundActivityStartPrivileges; - } - public void setPerceptible(boolean perceptible) { mPerceptible = perceptible; } @@ -487,7 +500,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } - boolean hasActivityInVisibleTask() { + private boolean hasActivityInVisibleTask() { for (int i = mActivities.size() - 1; i >= 0; --i) { TaskRecord task = mActivities.get(i).getTaskRecord(); if (task == null) { diff --git a/services/core/java/com/android/server/wm/WindowProcessControllerMap.java b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java new file mode 100644 index 000000000000..2767972f7ea0 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 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.wm; + +import android.util.ArraySet; +import android.util.SparseArray; + +import java.util.Map; +import java.util.HashMap; + +final class WindowProcessControllerMap { + + /** All processes we currently have running mapped by pid */ + private final SparseArray<WindowProcessController> mPidMap = new SparseArray<>(); + /** All processes we currently have running mapped by uid */ + private final Map<Integer, ArraySet<WindowProcessController>> mUidMap = new HashMap<>(); + + /** Retrieves a currently running process for pid. */ + WindowProcessController getProcess(int pid) { + return mPidMap.get(pid); + } + + /** Retrieves all currently running processes for uid. */ + ArraySet<WindowProcessController> getProcesses(int uid) { + return mUidMap.get(uid); + } + + SparseArray<WindowProcessController> getPidMap() { + return mPidMap; + } + + void put(int pid, WindowProcessController proc) { + // if there is a process for this pid already in mPidMap it'll get replaced automagically, + // but we actually need to remove it from mUidMap too before adding the new one + final WindowProcessController prevProc = mPidMap.get(pid); + if (prevProc != null) { + removeProcessFromUidMap(prevProc); + } + // put process into mPidMap + mPidMap.put(pid, proc); + // put process into mUidMap + final int uid = proc.mUid; + ArraySet<WindowProcessController> procSet = mUidMap.getOrDefault(uid, + new ArraySet<WindowProcessController>()); + procSet.add(proc); + mUidMap.put(uid, procSet); + } + + void remove(int pid) { + final WindowProcessController proc = mPidMap.get(pid); + if (proc != null) { + // remove process from mPidMap + mPidMap.remove(pid); + // remove process from mUidMap + removeProcessFromUidMap(proc); + } + } + + private void removeProcessFromUidMap(WindowProcessController proc) { + if (proc == null) { + return; + } + final int uid = proc.mUid; + ArraySet<WindowProcessController> procSet = mUidMap.get(uid); + if (procSet != null) { + procSet.remove(proc); + if (procSet.isEmpty()) { + mUidMap.remove(uid); + } + } + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java index d5cfab960171..5acf83aeb890 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java @@ -194,8 +194,17 @@ class AbUpdateInstaller extends UpdateInstaller { } UpdateEngine updateEngine = buildBoundUpdateEngine(); - updateEngine.applyPayload( - updatePath, mOffsetForUpdate, mSizeForUpdate, headerKeyValuePairs); + try { + updateEngine.applyPayload( + updatePath, mOffsetForUpdate, mSizeForUpdate, headerKeyValuePairs); + } catch (Exception e) { + // Prevent an automatic restart when an update is already being processed + // (http://b/124106342). + Log.w(UpdateInstaller.TAG, "Failed to install update from file.", e); + notifyCallbackOnError( + InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN, + "Failed to install update from file."); + } } private boolean updateStateForPayload() throws IOException { diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index c9aa63153a5d..32d7d026ff10 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -17,6 +17,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.frameworks.mockingservicestests"> + <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> + <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <application android:testOnly="true" diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java index fc74c972ed83..73b3b8b1ce3c 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java @@ -16,87 +16,119 @@ package com.android.server.display.color; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR; import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; + import android.hardware.display.ColorDisplayManager; import android.os.SystemProperties; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; @RunWith(AndroidJUnit4.class) public class DisplayTransformManagerTest { + private MockitoSession mSession; private DisplayTransformManager mDtm; private float[] mNightDisplayMatrix; + private HashMap<String, String> mSystemProperties; @Before public void setUp() { mDtm = new DisplayTransformManager(); mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY); - SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, null); - SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, null); + mSession = ExtendedMockito.mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .spyStatic(SystemProperties.class) + .startMocking(); + mSystemProperties = new HashMap<>(); + + doAnswer((Answer<Void>) invocationOnMock -> { + mSystemProperties.put(invocationOnMock.getArgument(0), + invocationOnMock.getArgument(1)); + return null; + } + ).when(() -> SystemProperties.set(anyString(), any())); + } + + @After + public void tearDown() throws Exception { + mSession.finishMocking(); + mSystemProperties.clear(); } @Test public void setColorMode_natural() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("0" /* managed */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_boosted() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("0" /* managed */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.1" /* boosted */); } @Test public void setColorMode_saturated() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("1" /* unmanaged */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_automatic() { mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo("2" /* enhanced */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_vendor() { mDtm.setColorMode(0x100, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) .isEqualTo(Integer.toString(0x100) /* pass-through */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) - .isEqualTo("1.0" /* default */); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) + .isEqualTo("1.0" /* natural */); } @Test public void setColorMode_outOfBounds() { mDtm.setColorMode(0x50, mNightDisplayMatrix); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null)) - .isEqualTo("" /* default */); - assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null)) - .isEqualTo("" /* default */); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR)) + .isEqualTo(null); + assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION)) + .isEqualTo(null); } } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 2cba9d022866..2977414fb302 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -17,6 +17,7 @@ package com.android.server.accessibility; import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_HOVER_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; @@ -116,6 +117,7 @@ public class MotionEventInjectorTest { MotionEvent mClickDownEvent; MotionEvent mClickUpEvent; + MotionEvent mHoverMoveEvent; ArgumentCaptor<MotionEvent> mCaptor1 = ArgumentCaptor.forClass(MotionEvent.class); ArgumentCaptor<MotionEvent> mCaptor2 = ArgumentCaptor.forClass(MotionEvent.class); @@ -152,6 +154,10 @@ public class MotionEventInjectorTest { CLICK_POINT.y, 0); mClickUpEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mHoverMoveEvent = MotionEvent.obtain(0, 0, ACTION_HOVER_MOVE, CLICK_POINT.x, CLICK_POINT.y, + 0); + mHoverMoveEvent.setSource(InputDevice.SOURCE_MOUSE); + mIsLineStart = allOf(IS_ACTION_DOWN, isAtPoint(LINE_START), hasStandardInitialization(), hasTimeFromDown(0)); mIsLineMiddle = allOf(IS_ACTION_MOVE, isAtPoint(LINE_END), hasStandardInitialization(), @@ -301,6 +307,23 @@ public class MotionEventInjectorTest { } @Test + public void + testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() + throws RemoteException { + EventStreamTransformation next = attachMockNext(mMotionEventInjector); + injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); + mMessageCapturingHandler.sendOneMessage(); // Send a motion event + mMotionEventInjector.onMotionEvent(mHoverMoveEvent, mHoverMoveEvent, 0); + mMessageCapturingHandler.sendAllMessages(); + + verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); + assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); + assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); + assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); + verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); + } + + @Test public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java index 5de41ea5e7d1..4de00f7b5565 100644 --- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java +++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import android.attention.AttentionManagerInternal; import android.attention.AttentionManagerInternal.AttentionCallbackInternal; +import android.content.pm.PackageManager; import android.os.PowerManager; import android.os.PowerManagerInternal; import android.os.SystemClock; @@ -49,6 +50,8 @@ import org.mockito.MockitoAnnotations; public class AttentionDetectorTest extends AndroidTestCase { @Mock + private PackageManager mPackageManager; + @Mock private AttentionManagerInternal mAttentionManagerInternal; @Mock private Runnable mOnUserAttention; @@ -60,6 +63,9 @@ public class AttentionDetectorTest extends AndroidTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); + when(mPackageManager.getAttentionServicePackageName()).thenReturn("com.google.android.as"); + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_GRANTED); when(mAttentionManagerInternal.checkAttention(anyLong(), any())) .thenReturn(true); mAttentionDetector = new TestableAttentionDetector(); @@ -108,6 +114,27 @@ public class AttentionDetectorTest extends AndroidTestCase { } @Test + public void testOnUserActivity_doesntCheckIfNotSufficientPermissions() { + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); + + long when = registerAttention(); + verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any()); + assertThat(mNextDimming).isEqualTo(when); + } + + @Test + public void testOnUserActivity_disablesSettingIfNotSufficientPermissions() { + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); + + registerAttention(); + boolean enabled = Settings.System.getIntForUser(getContext().getContentResolver(), + Settings.System.ADAPTIVE_SLEEP, 0, UserHandle.USER_CURRENT) == 1; + assertFalse(enabled); + } + + @Test public void testOnUserActivity_doesntCrashIfNoAttentionService() { mAttentionManagerInternal = null; registerAttention(); @@ -211,6 +238,8 @@ public class AttentionDetectorTest extends AndroidTestCase { TestableAttentionDetector() { super(AttentionDetectorTest.this.mOnUserAttention, new Object()); mAttentionManager = mAttentionManagerInternal; + mPackageManager = AttentionDetectorTest.this.mPackageManager; + mContentResolver = getContext().getContentResolver(); mMaximumExtensionMillis = 10000L; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 49ee8b3bba19..6be2c2e8c59e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -48,8 +48,8 @@ import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; import android.app.NotificationManager; +import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.graphics.Color; import android.media.AudioAttributes; import android.media.AudioManager; @@ -63,7 +63,6 @@ import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; -import android.testing.TestableContext; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; @@ -71,7 +70,6 @@ import android.view.accessibility.IAccessibilityManagerClient; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; import com.android.internal.util.IntPair; import com.android.server.UiServiceTestCase; import com.android.server.lights.Light; @@ -88,7 +86,6 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class BuzzBeepBlinkTest extends UiServiceTestCase { - private TestableContext mContext = spy(getContext()); @Mock AudioManager mAudioManager; @Mock Vibrator mVibrator; @Mock android.media.IRingtonePlayer mRingtonePlayer; @@ -99,8 +96,6 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationUsageStats mUsageStats; @Mock IAccessibilityManager mAccessibilityService; - @Mock - Resources mResources; private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; @@ -150,7 +145,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt()); assertTrue(accessibilityManager.isEnabled()); - mService = spy(new NotificationManagerService(mContext)); + mService = spy(new NotificationManagerService(getContext())); mService.setAudioManager(mAudioManager); mService.setVibrator(mVibrator); mService.setSystemReady(true); @@ -280,7 +275,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { boolean isLeanback) { NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH); - final Builder builder = new Builder(mContext) + final Builder builder = new Builder(getContext()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setPriority(Notification.PRIORITY_HIGH) @@ -326,14 +321,15 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { n.flags |= Notification.FLAG_INSISTENT; } - PackageManager packageManager = spy(mContext.getPackageManager()); - when(mContext.getPackageManager()).thenReturn(packageManager); + Context context = spy(getContext()); + PackageManager packageManager = spy(context.getPackageManager()); + when(context.getPackageManager()).thenReturn(packageManager); when(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) .thenReturn(isLeanback); StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid, mPid, n, mUser, null, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(mContext, sbn, channel); + NotificationRecord r = new NotificationRecord(context, sbn, channel); mService.addNotification(r); return r; } @@ -459,25 +455,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test - public void testNoBeepForAutomotiveIfEffectsDisabled() throws Exception { - when(mContext.getResources()).thenReturn(mResources); - when(mResources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive)) - .thenReturn(false); - mService.setIsAutomotive(true); - - NotificationRecord r = getBeepyNotification(); - - mService.buzzBeepBlinkLocked(r); - - verifyNeverBeep(); - assertFalse(r.isInterruptive()); - } - - @Test - public void testNoBeepForImportanceDefaultInAutomotiveIfEffectsEnabled() throws Exception { - when(mContext.getResources()).thenReturn(mResources); - when(mResources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive)) - .thenReturn(true); + public void testNoBeepForImportanceDefaultInAutomotive() throws Exception { mService.setIsAutomotive(true); NotificationRecord r = getBeepyNotification(); @@ -490,10 +468,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test - public void testBeepForImportanceHighInAutomotiveIfEffectsEnabled() throws Exception { - when(mContext.getResources()).thenReturn(mResources); - when(mResources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive)) - .thenReturn(true); + public void testBeepForImportanceHighInAutomotive() throws Exception { mService.setIsAutomotive(true); NotificationRecord r = getBeepyNotification(); @@ -1040,12 +1015,12 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { public void testEmptyUriSoundTreatedAsNoSound() throws Exception { NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, null); - final Notification n = new Builder(mContext, "test") + final Notification n = new Builder(getContext(), "test") .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid, mPid, n, mUser, null, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(mContext, sbn, channel); + NotificationRecord r = new NotificationRecord(getContext(), sbn, channel); mService.addNotification(r); mService.buzzBeepBlinkLocked(r); @@ -1094,13 +1069,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { @Test public void testCrossUserSoundMuted() throws Exception { - final Notification n = new Builder(mContext, "test") + final Notification n = new Builder(getContext(), "test") .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); int userId = mUser.getIdentifier() + 1; StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid, mPid, n, UserHandle.of(userId), null, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(mContext, sbn, + NotificationRecord r = new NotificationRecord(getContext(), sbn, new NotificationChannel("test", "test", IMPORTANCE_HIGH)); mService.buzzBeepBlinkLocked(r); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index 96db38b14ad5..a7bbe6e4cf02 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -87,7 +87,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { mController.doPendingActivityLaunches(resume); verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null), - eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null)); + eq(null), eq(startFlags), eq(resume), eq(null), eq(null)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 44aa55d07133..45d52195c5fd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -577,12 +577,27 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_callingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_realCallingUidProcessStateTop_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, + false, false, false, false, false, false); + runAndVerifyBackgroundActivityStartsSubtest( + "disallowed_hasForegroundActivities_aborted", true, + UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, + UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, + true, false, false, false, false, false); } /** * This test ensures that supported usecases aren't aborted when background starts are * disallowed. - * The scenarios each have only one condidion that makes them supported. + * The scenarios each have only one condition that makes them supported. */ @Test public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() { @@ -606,26 +621,11 @@ public class ActivityStarterTests extends ActivityTestsBase { UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_callingUidProcessStateTop_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - false, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( "disallowed_realCallingUidHasVisibleWindow_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1, false, false, false, false, false, false); runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_realCallingUidProcessStateTop_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP, - false, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( - "disallowed_hasForegroundActivities_notAborted", false, - UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, - UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, - true, false, false, false, false, false); - runAndVerifyBackgroundActivityStartsSubtest( "disallowed_callerIsRecents_notAborted", false, UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1, UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index c4009df27c1f..ca3f6846f74d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -52,6 +52,7 @@ import android.view.Display; import android.view.Surface; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -383,6 +384,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130392471) public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows for (int i = 0; i < 1000; i++) { diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 329af952c07a..bb574ceed4e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -48,6 +48,7 @@ import android.platform.test.annotations.Presubmit; import android.util.Log; import android.view.IWindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.server.am.AssistDataRequester; @@ -150,6 +151,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testRequestData() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -250,6 +252,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); @@ -260,6 +263,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 130388718) public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, !CALLER_ASSIST_SCREENSHOT_ALLOWED); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index af048586b425..3392bc43e568 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -712,7 +712,6 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(mTasks.get(4)); // Freeze the list - long freezeTime = SystemClock.elapsedRealtime(); mRecentTasks.setFreezeTaskListReordering(); assertTrue(mRecentTasks.isFreezeTaskListReorderingSet()); @@ -720,13 +719,11 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.add(mTasks.get(2)); mRecentTasks.add(mTasks.get(1)); - // Override the freeze timeout params to simulate the timeout (simulate the freeze at 100ms - // ago with a timeout of 1ms) - mRecentTasks.setFreezeTaskListTimeoutParams(freezeTime - 100, 1); - ActivityStack stack = mTasks.get(2).getStack(); stack.moveToFront("", mTasks.get(2)); doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack(); + + // Simulate the reset from the timeout mRecentTasks.resetFreezeTaskListReorderingOnTimeout(); assertFalse(mRecentTasks.isFreezeTaskListReorderingSet()); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 35a8ec37c758..263f6501bbf6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -50,8 +50,8 @@ public class RootWindowContainerTests extends WindowTestsBase { toastyToast.mHasSurface = true; app.mHasSurface = true; - assertTrue(toastyToast.isVisible()); - assertTrue(app.isVisible()); + assertTrue(toastyToast.isVisibleNow()); + assertTrue(app.isVisibleNow()); assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -60,7 +60,7 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID); toastyToast.mHasSurface = true; - assertTrue(toastyToast.isVisible()); + assertTrue(toastyToast.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } @@ -69,8 +69,8 @@ public class RootWindowContainerTests extends WindowTestsBase { final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID); final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID); - assertFalse(topBar.isVisible()); - assertFalse(app.isVisible()); + assertFalse(topBar.isVisibleNow()); + assertFalse(app.isVisibleNow()); assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 9722d2ccce99..62247d889485 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -39,6 +39,7 @@ import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; +import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.annotations.GuardedBy; @@ -78,6 +79,7 @@ public class TaskStackChangedListenerTest { @Test @Presubmit + @FlakyTest(bugId = 130388819) public void testTaskStackChanged_afterFinish() throws Exception { registerTaskStackChangedListener(new TaskStackListener() { @Override @@ -159,6 +161,7 @@ public class TaskStackChangedListenerTest { */ @Test @Presubmit + @FlakyTest(bugId = 130388819) public void testTaskChangeCallBacks() throws Exception { final Object[] params = new Object[2]; final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 78fca0f2e6ef..06bcdf8fcadf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -36,6 +36,7 @@ import android.view.Gravity; import android.view.IWindow; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.wm.utils.WmDisplayCutout; @@ -323,6 +324,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testCalculatePolicyCrop() { final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; @@ -423,6 +425,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testDisplayCutout() { // Regular fullscreen task and window WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); @@ -446,6 +449,7 @@ public class WindowFrameTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 130388666) public void testDisplayCutout_tempDisplayedBounds() { // Regular fullscreen task and window WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java new file mode 100644 index 000000000000..cb7bff3a4f15 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerMapTests.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 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.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link WindowProcessControllerMap} class. + * + * Build/Install/Run: + * atest WmTests:WindowProcessControllerMapTests + */ +@SmallTest +@Presubmit +public class WindowProcessControllerMapTests extends ActivityTestsBase { + + private static final int FAKE_UID1 = 666; + private static final int FAKE_UID2 = 667; + private static final int FAKE_PID1 = 668; + private static final int FAKE_PID2 = 669; + private static final int FAKE_PID3 = 670; + private static final int FAKE_PID4 = 671; + + private WindowProcessControllerMap mProcessMap; + private WindowProcessController pid1uid1; + private WindowProcessController pid1uid2; + private WindowProcessController pid2uid1; + private WindowProcessController pid3uid1; + private WindowProcessController pid4uid2; + + @Before + public void setUp() throws Exception { + mProcessMap = new WindowProcessControllerMap(); + pid1uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid1uid1.setPid(FAKE_PID1); + pid1uid2 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid1uid2.setPid(FAKE_PID1); + pid2uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid2uid1.setPid(FAKE_PID2); + pid3uid1 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid3uid1.setPid(FAKE_PID3); + pid4uid2 = new WindowProcessController( + mService, mService.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2, + UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); + pid4uid2.setPid(FAKE_PID4); + } + + @Test + public void testAdditionsAndRemovals() { + // test various additions and removals + mProcessMap.put(FAKE_PID1, pid1uid1); + mProcessMap.put(FAKE_PID2, pid2uid1); + assertEquals(pid1uid1, mProcessMap.getProcess(FAKE_PID1)); + assertEquals(pid2uid1, mProcessMap.getProcess(FAKE_PID2)); + ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertTrue(uid1processes.contains(pid2uid1)); + assertEquals(uid1processes.size(), 2); + + mProcessMap.remove(FAKE_PID2); + mProcessMap.put(FAKE_PID3, pid3uid1); + uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertFalse(uid1processes.contains(pid2uid1)); + assertTrue(uid1processes.contains(pid3uid1)); + assertEquals(uid1processes.size(), 2); + + mProcessMap.put(FAKE_PID4, pid4uid2); + ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2); + assertTrue(uid2processes.contains(pid4uid2)); + assertEquals(uid2processes.size(), 1); + + mProcessMap.remove(FAKE_PID1); + mProcessMap.remove(FAKE_PID3); + assertNull(mProcessMap.getProcesses(FAKE_UID1)); + assertEquals(mProcessMap.getProcess(FAKE_PID4), pid4uid2); + } + + @Test + public void testReplacement() { + // test that replacing a process is handled correctly + mProcessMap.put(FAKE_PID1, pid1uid1); + ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1); + assertTrue(uid1processes.contains(pid1uid1)); + assertEquals(uid1processes.size(), 1); + + mProcessMap.put(FAKE_PID1, pid1uid2); + assertNull(mProcessMap.getProcesses(FAKE_UID1)); + ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2); + assertTrue(uid2processes.contains(pid1uid2)); + assertEquals(uid2processes.size(), 1); + assertEquals(mProcessMap.getProcess(FAKE_PID1), pid1uid2); + } +} diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index cbcd40f15583..ebfa3a15639a 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -41,26 +41,12 @@ import java.util.List; /** * This service is implemented by an app that wishes to provide functionality for managing * phone calls. - * <p> - * There are three types of apps which Telecom can bind to when there exists a live (active or - * incoming) call: - * <ol> - * <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the - * in-call user interface while the device is in a call. A device is bundled with a system - * provided default dialer/phone app. The user may choose a single app to take over this role - * from the system app.</li> - * <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which - * provides the in-call user interface while the device is in a call and the device is in car - * mode. The user may choose a single app to fill this role.</li> - * <li>Call Companion app - a call companion app is one which provides no user interface itself, - * but exposes call information to another display surface, such as a wearable device. The - * user may choose multiple apps to fill this role.</li> - * </ol> - * <p> - * Apps which wish to fulfill one of the above roles use the {@link android.app.role.RoleManager} - * to request that they fill the desired role. - * * <h2>Becoming the Default Phone App</h2> + * The default dialer/phone app is one which provides the in-call user interface while the device is + * in a call. A device is bundled with a system provided default dialer/phone app. The user may + * choose a single app to take over this role from the system app. An app which wishes to fulfill + * one this role uses the {@code android.app.role.RoleManager} to request that they fill the role. + * <p> * An app filling the role of the default phone app provides a user interface while the device is in * a call, and the device is not in car mode. * <p> @@ -193,47 +179,6 @@ import java.util.List; * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build()); * }</pre> * <p> - * <h2>Becoming the Default Car-mode Phone App</h2> - * An app filling the role of the default car-mode dialer/phone app provides a user interface while - * the device is in a call, and in car mode. See - * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode. - * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead - * of the usual dialer/phone app. - * <p> - * Similar to the requirements for becoming the default dialer/phone app, your app must declare a - * manifest entry for its {@link InCallService} implementation. Your manifest entry should ensure - * the following conditions are met: - * <ul> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> - * <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to - * {@code true}<li> - * <li>Your app must request the permission - * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> - * </ul> - * <p> - * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER} in order to - * become the default (see <a href="#requestRole">above</a> for how to request your app fills this - * role). - * - * <h2>Becoming a Call Companion App</h2> - * An app which fills the companion app role does not directly provide a user interface while the - * device is in a call. Instead, it is typically used to relay information about calls to another - * display surface, such as a wearable device. - * <p> - * Similar to the requirements for becoming the default dialer/phone app, your app must declare a - * manifest entry for its {@link InCallService} implementation. Your manifest entry should - * ensure the following conditions are met: - * <ul> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> - * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} - * metadata.</li> - * <li>Your app must request the permission - * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> - * </ul> - * <p> - * Your app should request to fill the role {@code android.app.role.CALL_COMPANION} in order to - * become a call companion app (see <a href="#requestRole">above</a> for how to request your app - * fills this role). */ public abstract class InCallService extends Service { diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index 71a28b575394..eb568e04ebf3 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -17,6 +17,7 @@ package android.telecom; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Build; @@ -174,4 +175,21 @@ public final class PhoneAccountHandle implements Parcelable { in.readString(), UserHandle.CREATOR.createFromParcel(in)); } + + /** + * Determines if two {@link PhoneAccountHandle}s are from the same package. + * + * @param a Phone account handle to check for same {@link ConnectionService} package. + * @param b Other phone account handle to check for same {@link ConnectionService} package. + * @return {@code true} if the two {@link PhoneAccountHandle}s passed in belong to the same + * {@link ConnectionService} / package, {@code false} otherwise. Note: {@code null} phone + * account handles are considered equivalent to other {@code null} phone account handles. + * @hide + */ + public static boolean areFromSamePackage(@Nullable PhoneAccountHandle a, + @Nullable PhoneAccountHandle b) { + String aPackageName = a != null ? a.getComponentName().getPackageName() : null; + String bPackageName = b != null ? b.getComponentName().getPackageName() : null; + return Objects.equals(aPackageName, bPackageName); + } } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 391d788cfe72..db6319871540 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -16,7 +16,6 @@ package android.telecom; import android.Manifest; import android.annotation.IntDef; -import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; @@ -497,6 +496,9 @@ public class TelecomManager { * Dialer implementations (see {@link #getDefaultDialerPackage()}) which would also like to * override the system provided ringing should set this meta-data to {@code true} in the * manifest registration of their {@link InCallService}. + * <p> + * When {@code true}, it is the {@link InCallService}'s responsibility to play a ringtone for + * all incoming calls. */ public static final String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING"; @@ -1495,8 +1497,21 @@ public class TelecomManager { /** * Silences the ringer if a ringing call exists. - * - * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * <p> + * This method can only be relied upon to stop the ringtone for a call if the ringtone has + * already started playing. It is intended to handle use-cases such as silencing a ringing call + * when the user presses the volume button during ringing. + * <p> + * If this method is called prior to when the ringtone begins playing, the ringtone will not be + * silenced. As such it is not intended as a means to avoid playing of a ringtone. + * <p> + * A dialer app which wants to have more control over ringtone playing should declare + * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in the manifest entry for their + * {@link InCallService} implementation to indicate that the app wants to be responsible for + * playing the ringtone for all incoming calls. + * <p> + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or that the + * app fills the dialer role (see {@link #getDefaultDialerPackage()}). */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger() { diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 2d8a8cbae59f..037e47520c94 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -3394,6 +3394,7 @@ public final class Telephony { * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM, * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id. */ + @NonNull public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers"); /** @@ -3406,6 +3407,7 @@ public final class Telephony { * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM, * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id. */ + @NonNull public static final Uri SIM_APN_URI = Uri.parse( "content://telephony/carriers/sim_apn_list"); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9f6528bc4709..d2f88bbda654 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2804,7 +2804,7 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = - "key_subscription_group_uuid_string"; + "subscription_group_uuid_string"; /** * A boolean property indicating whether this subscription should be managed as an opportunistic @@ -2819,7 +2819,7 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = - "key_is_opportunistic_subscription_bool"; + "is_opportunistic_subscription_bool"; /** * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR, diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index cf15b92ae640..c57f9e63f9db 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -39,6 +39,7 @@ import android.util.DisplayMetrics; import android.util.Log; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -123,6 +124,16 @@ public class SubscriptionInfo implements Parcelable { private String mMnc; /** + * EHPLMNs associated with the subscription + */ + private String[] mEhplmns; + + /** + * HPLMNs associated with the subscription + */ + private String[] mHplmns; + + /** * ISO Country code for the subscription's provider */ private String mCountryIso; @@ -316,6 +327,14 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) { + mEhplmns = ehplmns; + mHplmns = hplmns; + } + + /** * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a * user interface. * @@ -467,6 +486,20 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public List<String> getEhplmns() { + return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns); + } + + /** + * @hide + */ + public List<String> getHplmns() { + return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns); + } + + /** * @return the profile class of this subscription. * @hide */ @@ -600,7 +633,7 @@ public class SubscriptionInfo implements Parcelable { String mcc = source.readString(); String mnc = source.readString(); String countryIso = source.readString(); - Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source); + Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader()); boolean isEmbedded = source.readBoolean(); UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR); String cardString = source.readString(); @@ -611,11 +644,15 @@ public class SubscriptionInfo implements Parcelable { int carrierid = source.readInt(); int profileClass = source.readInt(); int subType = source.readInt(); - - return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, - nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, - isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID, - isGroupDisabled, carrierid, profileClass, subType); + String[] ehplmns = source.readStringArray(); + String[] hplmns = source.readStringArray(); + + SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, + carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, + countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic, + groupUUID, isGroupDisabled, carrierid, profileClass, subType); + info.setAssociatedPlmns(ehplmns, hplmns); + return info; } @Override @@ -638,7 +675,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeString(mMcc); dest.writeString(mMnc); dest.writeString(mCountryIso); - mIconBitmap.writeToParcel(dest, flags); + dest.writeParcelable(mIconBitmap, flags); dest.writeBoolean(mIsEmbedded); dest.writeTypedArray(mAccessRules, flags); dest.writeString(mCardString); @@ -649,6 +686,8 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); dest.writeInt(mSubscriptionType); + dest.writeStringArray(mEhplmns); + dest.writeStringArray(mHplmns); } @Override @@ -686,6 +725,8 @@ public class SubscriptionInfo implements Parcelable { + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID + " mIsGroupDisabled=" + mIsGroupDisabled + " profileClass=" + mProfileClass + + " ehplmns = " + Arrays.toString(mEhplmns) + + " hplmns = " + Arrays.toString(mHplmns) + " subscriptionType=" + mSubscriptionType + "}"; } @@ -729,6 +770,8 @@ public class SubscriptionInfo implements Parcelable { && TextUtils.equals(mDisplayName, toCompare.mDisplayName) && TextUtils.equals(mCarrierName, toCompare.mCarrierName) && Arrays.equals(mAccessRules, toCompare.mAccessRules) - && mProfileClass == toCompare.mProfileClass; + && mProfileClass == toCompare.mProfileClass + && Arrays.equals(mEhplmns, toCompare.mEhplmns) + && Arrays.equals(mHplmns, toCompare.mHplmns); } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 0c6341111029..0808adf26aef 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -458,6 +458,18 @@ public class SubscriptionManager { public static final String CARRIER_ID = "carrier_id"; /** + * @hide A comma-separated list of EHPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String EHPLMNS = "ehplmns"; + + /** + * @hide A comma-separated list of HPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String HPLMNS = "hplmns"; + + /** * TelephonyProvider column name for the MCC associated with a SIM, stored as a string. * <P>Type: TEXT (String)</P> * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0d3bc1db831f..2bd4f8f336fd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10376,10 +10376,10 @@ public class TelephonyManager { * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull @@ -10429,10 +10429,10 @@ public class TelephonyManager { * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li> * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li> * </ol> - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull |